Getting multiple results in a single query - mysql

I need to know student - student ID, first name, last name. Those have not seen an event at a particular given Auditorium. I have to list these students in ascending last name order (through one query). Run the query twice, showing results for the Auditorium “London Theatre” in one run and “Brentwood Hall” in the second run.
I have no clue what this first and second run means. Also please check if the below will work for first run. I am thinking of creating a view and storing the first run, and writing the same query with "Brentwood Hall" and storing it in the second view. However, how will I display 2 views as part of same query then?
SELECT op.StudentID
, s.FirstName
, s.LastName
FROM auditorium a
JOIN audievent e
ON a.auditoriumID = e.AuditoriumID
JOIN reserver r
ON e.EventID = r.EventID
JOIN OrderProcessor op
ON r.OrderID = op.OrderID
JOIN Student s
ON op.StudentID = s.StudentID
WHERE op.StudentID NOT IN ( SELECT DISTINCT op.StudentID
FROM OrderProcessor op
LEFT
JOIN reserver r
ON op.OrderID = r.OrderID
LEFT
JOIN AudiEvent e
ON r.AuditoriumID = e.AuditoriumID
WHERE e.EventID NOT IN ( SELECT EventID FROM reserver)
)
AND a.AuditoriumName = 'London Theatre'
GROUP
BY op.StudentID;
OUTPUT:-
StudentID FirstName LastName
ID1 Andy Hall
ID2 Andy Halls
ID3 Mush Peters
ID4 Garry Hiegl
INPUT:-
Auditorium
AudiID AudiName
Audi01 London Theatre
Audi02 Brentwood Hall
Audi03 County Hall
AudiEvent
EventID AudiID
1 Audi01
2 Audi01
3 Audi01
4 Audi01
5 Audi01
6 Audi01
7 Audi01
8 Audi01
9 Audi01
10 Audi01
11 Audi02
12 Audi02
13 Audi02
14 Audi02
15 Audi02
16 Audi03
17 Audi03
18 Audi03
19 Audi03
20 Audi03
Reserver
ReserverID OrderID AudiID EventID
1 1 Audi01 1
2 1 Audi01 2
3 2 Audi01 3
4 2 Audi01 4
5 2 Audi02 14
6 3 Audi02 15
7 3 Audi02 11
8 4 Audi03 18
9 4 Audi03 19
10 4 Audi03 20
OrderProcessor
OrderID StudentID
1 ID01
2 ID02
3 ID03
4 ID04
Student
StudentID FirstName LastName
ID1 Andy Hall
ID2 Andy Halls
ID3 Mush Peters
ID4 Garry Hiegl

As #wildplasser mentioned, NOT EXISTS is perfect for this:
SELECT studentId, student.firstName, student.lastName
FROM Student
WHERE NOT EXISTS (SELECT 1
FROM OrderProcessor
JOIN Reserver
ON Reserver.orderId = OrderProcessor.orderId
JOIN AudiEvent
ON AudiEvent.eventId = Reserver.eventId
JOIN Auditorium
ON Auditorium.audiId = AudiEvent.audiId
AND Auditorium.audiName = 'London Theatre'
WHERE OrderProcessor.studentId = Student.studentId)
(working SQL Fiddle example)
The necessary changes to get students who haven't seen events at the 'Brentwood Hall' is left as an exercise to the reader.

Related

SQL: how to get membership based on ALL from a given cohort

I have the following tables in a MySQL database:
team
team_id name
3 Rangers
12 Capitals
19 Red Wings
4 Bruins
212 Avalanche
102 Flyers
20 Islanders
50 Sabres
7 Stars
player
id name
2 Zach
1 Deb
17 William
9 Viktor
12 Andrew
41 Chris
22 Bobby
5 Phil
3 Roy
92 Li
6 Juan
players_in
team_id player_id points
3 2 42
212 2 19
3 12 18
19 12 2
3 41 2
4 41 1
212 41 78
212 17 1
19 41 4
12 41 2
3 17 6
4 1 9
102 1 40
102 22 7
20 22 19
20 5 22
50 3 20
12 92 15
12 17 8
7 6 12
Here is a SQL Fiddle with the data: http://www.sqlfiddle.com/#!9/989ebe/1
I would like to get the name and id of the players who have played on ALL of the teams that Zach has played on.
In this case, Zach has played for the Rangers and the Avalanche.
Therefore, the desired result set would be:
name id
William 17
Chris 41
(because these players were part of both the Rangers and the Avalanche teams)
How would I do this?
Thanks!
select distinct p.*
from player p
join players_in pi on pi.player_id = p.id
join player p2 on p2.name = 'Zach'
join players_in pi2 on pi2.team_id = pi.team_id
and pi2.player_id = p2.id
where
p.name <> 'Zach'
and not exists (select 1 from players_in pi3
where pi3.player_id = p2.id
and pi3.team_id not in (select team_id
from players_in pi4
where pi4.player_id = p.id));
First of all I've joined players_in (pi) with players (p) obtaining the set of all players and theirs teams.
Second, cross joined player zack joined with player_in (pi2) obtaining the set of Zach's teams. Joined pi2 with pi I've obtained the set of all player that had played in a Zach's team.
Now the where conditions:
p.name <> 'Zach' will exclude Zach from my list.
The not exists condition is the hard part of the query.
I've selected all Zach teams again (pi3) not in the set of the player's (p) team,
SQL Fiddle here
Your requirement could be translated to: searching for players which there's not exists any Jack's team that they don't play in. Corresponding query could be:
SELECT
DISTINCT p1.name, p1.id
FROM
player p1
INNER JOIN players_in pin1 ON p1.id = pin1.player_id
WHERE
name != 'Zach'
AND NOT EXISTS (
SELECT 1
FROM
team t
INNER JOIN players_in pin2 ON t.team_id = pin2.team_id
INNER JOIN player p2 ON p2.id = pin2.player_id
WHERE
p2.name = 'Zach'
AND NOT EXISTS (SELECT 1
FROM players_in pin3
WHERE pin2.team_id = pin3.team_id
AND pin1.player_id = pin3.player_id)
);
Demo: http://www.sqlfiddle.com/#!9/989ebe/61
Using a cte for Zach's games and then checking all potential memberships based on team_id existence in the cte's values:
with cte as (
select pi1.team_id from players_in pi1 join player p2 on p2.id = pi1.player_id
where p2.name = 'Zach'
)
select p.* from player p where (select count(*) from cte c) = (select
sum(pi1.team_id in (select c.team_id from cte c))
from players_in pi1 where pi1.player_id = p.id) and p.name != 'Zach'
See fiddle.

sql query to count votes, groub by candidate_id, position_id

table VOTES
id
voters_id
candidate_id
positions_id
1
xxx
18
6
2
xxx
18
6
3
xxx
18
6
4
xxx
18
6
5
xxx
19
6
6
xxx
19
6
7
xxx
22
20
8
xxx
22
20
table POSITIONS
id
title
6
president
20
mayor
table candidates
id
name
18
mark
19
john
22
eddie
I HAVE THESE THEERE TABLES, I NEED A QUERY FOR THIS OUTPUT
total_votes
candidate_id
candidate_name
position_id
position_name
4
18
mark
6
president
2
19
mark
6
president
2
22
eddie
20
mayor
Use:
select v.total_votes,
v.candidate_id,
c.name as candidate_name,
v.position_id ,
p.title as position_name
from (select COUNT(*) as total_votes,
candidate_id,
position_id
from votes
GROUP BY candidate_id, position_id
) as v
INNER JOIN positions p on v.position_id=p.id
INNER JOIN candidates c on c.id=v.candidate_id ;
Result:
total_votes candidate_id candidate_name position_id position_name
4 18 mark 6 president
2 19 john 6 president
2 22 eddie 20 mayor
Note. Aggregation always comes after the join, that's why you need to do the aggregation on a subquery
https://dbfiddle.uk/7q9GUm0y
can i ask, if i would add the percentage, counting the SUM of total
votes, on the votes obteined from a single candidate, how should i do
it?
select v.total_votes,
round(((v.total_votes * 100) / temp.tot_voters),2) AS Percentage,
concat(round(((v.total_votes * 100) / temp.tot_voters),2),'%') AS Percentage_1,
v.candidate_id,
c.name as candidate_name,
v.position_id ,
p.title as position_name
from (select COUNT(*) as total_votes,
candidate_id,
position_id
from votes
GROUP BY candidate_id, position_id
) as v
CROSS JOIN (select count(voters_id) as tot_voters from votes) temp
INNER JOIN positions p on v.position_id=p.id
INNER JOIN candidates c on c.id=v.candidate_id ;
https://dbfiddle.uk/wBTbVVlf

SQL Inner Join statement not giving desired results

Hopefully someone can give me a hand here. I have the following two tables:
Table: locations
location_id user_id city state
1 1 Los Angeles CA
2 1 New York NY
3 1 Chicago IL
4 2 Dallas TX
5 3 Denver CO
6 4 Miami FL
7 5 Atlanta GA
Table: events
event_id user_id event_name event_date
1 1 My Event 1 2017-02-01
2 2 My Event 2 2017-03-01
3 3 My Event 3 2017-04-01
4 4 My Event 4 2017-05-01
5 5 My Event 5 2017-06-01
I am running the following query:
SELECT e.event_id, e.user_id, e.event_name, e.event_date,
l.user_id, l.city, l.state
FROM events e
INNER JOIN locations l
ON e.user_id = l.user_id
ORDER BY e.event_date ASC
I am trying just to get JUST the records in the events table, but also pull the corresponding city and state that match the user_id that both tables have in common. The output should be:
event_id user_id event_name event_date city state
1 1 My Event 1 2017-02-01 Los Angeles CA
2 2 My Event 2 2017-03-01 Dallas TX
3 3 My Event 3 2017-04-01 Denver CO
4 4 My Event 4 2017-05-01 Miami FL
5 5 My Event 5 2017-06-01 Atlanta GA
Can anyone point me to my error in the SQL statement?
You never gave us the logic for deciding which location to choose for a given user. One approach would be to take the minimum location_id associated with a given user:
SELECT t1.*,
COALESCE(t2.city, 'NA'),
COALESCE(t2.state, 'NA')
FROM events t1
LEFT JOIN locations t2
ON t1.user_id = t2.user_id
INNER JOIN
(
SELECT user_id, MIN(location_id) AS min_location_id
FROM locations
GROUP BY user_id
) t3
ON t2.user_id = t3.user_id AND
t2.location_id = t3.min_location_id
That's quite impossible, here the issue is for user with id 1 you have 3 tuples in the locations table , which city to select is the big question.
1 1 Los Angeles CA
2 1 New York NY
3 1 Chicago IL

mysql query: how to

here's my (simplified) table structure:
table: category_main
id name
-------------
1 food
2 vegetable
table category_sub
id id_catmain name
---------------------
10 1 cake
11 1 chocolate
12 1 burger
13 2 apple
14 2 banana
table images
id id_catsub filename views
-------------------------------------
1 10 cake1.jpg 11
2 10 cake2.jpg 24
3 10 cake3.jpg 65
4 11 chocolate1.jpg 31
5 11 chocolate2.jpg 62
6 11 chocolate3.jpg 32
7 11 chocolate4.jpg 58
8 12 burger1.jpg 23
9 12 burger2.jpg 43
10 12 burger3.jpg 76
11 13 apple1.jpg 29
11 13 apple2.jpg 67
11 14 banana1.jpg 78
desired output:
id name total_views
----------------------------
1 food 425
2 vegetable 174
as you can see i want to get the total views for each main category.
currently i'm running a loop for each subcategory but there must be an easier and faster way :/
thanks
Double LEFT JOIN + aggregation will do the job.
SELECT cm.id, cm.name, sum(images.views) as views
FROM category_main as cm
LEFT JOIN category_sub as cs ON cs.id_catmain = cm.id
LEFT JOIN images ON images.id_carsub = cs.id
GROUP BY cm.id
ORDER BY views DESC;
LEFT JOIN (instead of JOIN) will make you sure that you have all categories listed even if there's no subcategory or image in it. If you don't want empty categories to be listed, then use JOIN.
SELECT c.id AS id, c.name AS name, sum(i.views) AS total_views
FROM category_main c, category_sub s, images i
WHERE c.id=s.id_catmain and s.id=i.id_catsub
GROUP BY c.id,c.name;
simply join the three tables, and then you can sum the views grouped by the id's:
select cm.id, cm.name, sum(i.views) as total_views from
category_main as cm inner join category_sub as cs on cm.id = cs.id_catmain
inner join cs.id = i.id_catsub group by cm.id

Add total of 3 rows for specific id

I have three tables:
Students
-------------------------------------------------------------
studentId first last gender weight
-------------------------------------------------------------
1 John Doe m 185
2 John Doe2 m 130
3 John Doe3 m 250
Lifts
-------------------
liftId name
-------------------
1 Bench Press
2 Power Clean
3 Parallel Squat
4 Deadlift
5 Shoulder Press
StudentLifts
------------------------------------------------
studentLiftId studentId liftId weight
------------------------------------------------
1 1 1 185
2 2 3 130
3 3 1 190
4 1 2 120
5 2 1 155
6 3 2 145
7 1 1 135
8 1 1 205
9 2 3 200
10 1 3 150
11 2 2 110
12 3 3 250
I would like to have four top lists:
Bench Press
Parallel Squat
Power Clean
Total of the above 3
I can successfully grab a top list for each specific lift using the following query:
SELECT s.studentId, s.first, s.last, s.gender, s.weight, l.name, sl.weight
FROM Students s
LEFT JOIN (
SELECT *
FROM StudentLifts
ORDER BY weight DESC
) sl ON sl.studentId = s.studentId
LEFT JOIN Lifts l ON l.liftId = sl.liftId
WHERE l.name = 'Bench Press'
AND s.gender = 'm'
AND s.weight > 170
GROUP BY s.studentId
ORDER BY sl.weight DESC
However, I am stuck on how to add the highest total of each lift for each student. How can I first find the highest total for each student in each lift, and then add them up to get a total of all three lifts?
Edit
The result set that I am looking for would be something like:
-------------------------------------------------
studentId first last weight
-------------------------------------------------
3 John Doe3 585
1 John Doe 475
2 John Doe2 465
I also forgot to mention that I would actually like two lists, one for students above 170 and one for students below 170.
SELECT -- join student a total weight to the student table
A.studentId,
A.first,
A.last,
C.totalWeight
FROM
Student A,
(
SELECT -- for each studet add the max weights
sum(B.maxWeight) as totalWeight,
B.studentID
FROM (
SELECT -- for each (student,lift) select the max weight
max(weight) as maxWeight,
studentId,
liftID
FROM
StudentLifts
GROUP BY
studentId,
liftID
) B
GROUP BY
studentId
) C
WHERE
A.studentID = C.studentId
-- AND A.weight >= 170
-- AND A.weight < 170
-- pick one here to generate on of the two lists.