I am so totally lost.
Working on a database for my co-rec team. Players, Matches, Available players for a match, chosen players for a match, etc.....
The first major step I'd like is to be able to combine Players, Matches and Available to get a list of matches with the number of Women and number of Men available.
Here are my tables:
Players (id, Gender, Name, ....)
id Gender Name
1 M David
2 M Alberto
3 F Alison
4 F Karen
5 F Callie
6 M Stephan
Matches (id, ...)
id
1
2
3
Available (id, matchID, playerID)
id matchID PlayerID
1 1 1
2 1 8
3 1 11
... ... ...
16 2 1
17 2 2
18 2 15
... ... ...
26 3 6
27 3 7
28 3 18
Desired Result
Match Women Men Total
1 5 10 15
2 4 6 10
3 6 10 16
... ... ... ...
Here's the closest I've got (just this morning):
select m.id, p.gender
from matches m
inner join available a on m.id = a.matchid
inner join players p on p.id = a.playerid
Morning clarity:
select m.id,
sum(case when p.gender="Male" then 1 else 0 end) "Males",
sum(case when p.gender="Female" then 1 else 0 end) "Females",
count(p.gender) "Total"
from matches m
inner join available a on m.id = a.matchid
inner join players p on p.id = a.playerid
group by m.id
Related
I have four tables detailing an amusement park and its guests' ride history.
Categories
c_id name
1 Thrill
2 Leisure
3 Kiddie
Rides
r_id c_id
1 1
2 1
3 2
4 2
5 3
6 3
guest_history
h_id g_id
1 1
2 1
3 2
4 3
history_items
h_id r_id
1 5
2 6
3 1
3 2
4 5
How would I get all of the guests (g_id's) that have either rode all of the kiddie rides or none of the kiddie rides?
Expected Output would be:
g_id
1
2
I can't seem to figure out what the easiest way to go about it would be. I can only seem to conjure up a table that contains all of the cases that a guest has rode a kiddie ride. My attempt was a 4-way inner join of the tables and to filter out on the c_id = "Kiddie". Any help would be appreciated.
You can try this below logic-
3 is fixed in the query to get category "Kiddie"
DEMO HERE
SELECT A.g_id,COUNT(C.r_id)
FROM guest_history A
INNER JOIN history_items B ON A.h_id = B.h_id
INNER JOIN Rides C ON B.r_id = C.r_id AND C.c_id = 3
GROUP BY A.g_id
HAVING COUNT(DISTINCT B.r_id) = (SELECT COUNT(r_id) FROM Rides WHERE c_id = 3)
OR COUNT(DISTINCT B.r_id) = 0
SELECT g_id
FROM Categories
NATURAL JOIN Rides
NATURAL JOIN guest_history
NATURAL JOIN history_items
GROUP BY g_id
HAVING COUNT(DISTINCT r_id) IN (0,
(SELECT COUNT(DISTINCT r_id)
FROM Categories
NATURAL JOIN Rides
WHERE name = 'Kiddie')
)
fiddle
I have two tables:
LLOAN
LOANID SOURCEID LOAN_COMPANY ETC
1 1 3
2 1 3
3 1 1
4 2 1
5 2 1
6 2 1
7 3 1
8 3 1
COMPANY
CompanyID CountryID CompanyIDLLAS
1 1 1
2 1 2
3 1 3
4 2 1
5 3 1
6 4 1
And I want to join them. The SourceID refers to the CountryID and the LOAN_COMPANY refers to the CompanyID. Only country '1' has multiple companies, all the others just have one.
How can I join these two tables correctly? I've tried many different things, of which this came the closest:
SELECT Count(c.CompanyID) FROM dbo.LLOAN As l
LEFT JOIN dbo.Company As c ON c.CountryID = l.SourceID AND c.CompanyID = l.LOAN_COMPANY
But it leaves many rows blank. What is the correct way to join two tables with two conditions?
Try below Query:
SELECT Count(c.CompanyID)
FROM dbo.LLOAN As LL
LEFT JOIN dbo.Company As C
ON (C.CountryID = LL.SourceID)
AND (C.CompanyID = LL.LOAN_COMPANY)
You can group the condition using paranthesis like this:
SELECT Count(c.CompanyID)
FROM dbo.LLOAN As l
LEFT JOIN dbo.Company As c ON (c.CountryID = l.SourceID) AND (c.CompanyID = l.LOAN_COMPANY)
I have two tables. One is the Course table and the second is the Teacher table. I want to get all Teacher who does not teach 'Math'. How can I do this?
Course Table
course_id course teacher_id marks
1 Physics 1 60
2 Math 1 60
3 Chemestry 1 60
4 English 2 60
5 Hindi 2 60
6 Physics 2 60
7 Chemestry 3 60
8 English 4 60
9 Math 5 60
10 Math 6 60
Teacher Table
teacher_id name salary gender
1 Teacher1 20 1
2 Teacher2 30 1
3 Teacher3 40 2
4 Teacher4 50 2
5 Teacher5 60 1
6 Teacher6 70 2
I want to get all teacher who does not teachs math.
You need to join both the tables on teacher_id and then filter out the rows based on the course.
SQL> SELECT DISTINCT t.name
2 FROM course c,
3 teacher t
4 WHERE c.teacher_id = t.teacher_id
5 AND c.course <> 'Math';
NAME
--------
Teacher2
Teacher1
Teacher4
Teacher3
SQL>
EDIT Since you have teachers teaching multiple courses, you need to filter out further:
SQL> WITH DATA AS
2 (SELECT c.*,
3 t.name
4 FROM course c,
5 teacher t
6 WHERE c.teacher_id = t.teacher_id
7 AND c.course <> 'Math'
8 )
9 SELECT DISTINCT name
10 FROM data
11 WHERE teacher_id NOT IN
12 (SELECT teacher_id FROM course WHERE course = 'Math'
13 )
14 /
NAME
--------
Teacher2
Teacher4
Teacher3
SQL>
NOTE Please keep in mind that the other solution using NOT EXISTS clause is better in terms of performance, since the table scans are less and even index scans. With proper indexes, the not exists query would be an optimal method.
select *
from teacher t
where not exists
(select 1 from course c where c.teacher_id = t.teacher_id and c.course = 'Math')
#LalitKumarB
Ben is absolutely right
inner join
select t.teacher_id, t.name
from teacher t, Course c
where c.course='math' and t.teacher_id=c.teacher_id;
EDIT
you can do it using join and subquery.
select * from course join teacher
on course.teacher_id=teacher.teacher_id
where teacher.teacher_id not in
(select distinct teacher_id from course where course = 'Math')
Select * from Teacher
join Course
on Teacher.teacher.id = Course.teacher.id
where Course.course != 'Math'
select
t.name
from teacher t
left join course c
on c.teacher_id = t.teacher_id
where c.course_id <> 2
Selecting the Top n Results, I've seen the numerous posts and great articles on here about how to do it but I am struggling to do it with my data set. Most of the examples focus on data sets without the need for additional joins.
I've been trying to apply the examples from http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/ to my query without much success.
Three tables exist Person, Credit and Media.
Person links to Credit and Credit to Media.
The query below should return the top 5 medias per person, however it doesn't, where have I gone wrong?
SELECT
p.id AS person_id,
c.id AS credit_id,
m.id AS media_id, m.rating_average
FROM person p
INNER JOIN credit c ON c.person_id = p.id
INNER JOIN media m ON m.id = c.media_id
where (
select count(*) from media as m2
inner JOIN credit c2 on m2.id=c2.media_id
where c2.person_id = c.person_id and m2.rating_average >= m.rating_average
) <= 5
Clarification:
Top Medias are calculated from those with the highest rating_average.
Update:
SQLFiddle http://sqlfiddle.com/#!9/eb0fd
Desired output for top 3 medias (m) per person (p). Obviously I would like to do be able this for the top 5 medias but this is only test data.
p m c rating_average
1 9 27 9
1 7 28 8
1 1 1 8
2 1 5 8
2 4 8 8
2 7 29 8
3 4 10 8
3 3 9 6
3 5 11 5
4 3 13 6
4 5 14 5
4 6 15 3
5 4 16 8
5 5 17 5
5 6 18 3
6 6 19 3
7 7 20 8
8 9 23 9
8 1 21 8
8 8 22 0
9 1 24 8
9 7 26 8
9 5 25 5
i think i solve it :)
First here is one solution based on the way you started. But there is a catch I couldn't solve it to show exact 3 (or whatever number you choose i pick 3 for example) row for each person_id. Problem is that solution is based on counting how many rows is there with the rating_average greater then current row. So if you have 5 same top value you could choose to show all 5 or not to show them at all and that's not good. So here is the way you do that... (of course this is example where if you have 4 top value you show them all (I think that no make sense at all to not show the data))...
SELECT t1.person_id, t1.credit_id, t1.media_id, t1.rating_average
FROM (SELECT p.id AS person_id, c.id AS credit_id, m.id AS media_id,
m.rating_average AS rating_average
FROM person p
INNER JOIN credit c ON c.person_id = p.id
INNER JOIN media m ON m.id = c.media_id) as t1
WHERE (SELECT COUNT(*)
FROM (SELECT p.id AS person_id, c.id AS credit_id, m.id AS media_id,
m.rating_average AS rating_average
FROM person p
INNER JOIN credit c ON c.person_id = p.id
INNER JOIN media m ON m.id = c.media_id) AS t2
WHERE t2.person_id = t1.person_id AND t2.rating_average > t1.rating_average) < 3
ORDER BY person_id ASC, rating_average DESC
Important: This solution can work (to show exact 3 rows for each person) if you don't have value that repeat it self... Here is the Fiddle http://sqlfiddle.com/#!9/eb0fd/64 you can see the problem where person_id is 1!
After that i played a little more and make it work just as you wanted in the question i think. Here is a code for that:
SET #num := 0, #person := 0;
SELECT person_id, credit_id, media_id, rating_average, rowNumber
FROM (SELECT t1.person_id, t1.credit_id, t1.media_id, t1.rating_average,
#num := if(#person = t1.person_id, #num + 1, 1) AS rowNumber,
#person := t1.person_id
FROM (SELECT p.id AS person_id, c.id AS credit_id, m.id AS media_id,
m.rating_average AS rating_average
FROM person p
INNER JOIN credit c ON c.person_id = p.id
INNER JOIN media m ON m.id = c.media_id
ORDER BY p.id ASC, m.rating_average DESC) as t1) as t2
WHERE rowNumber <= 3
Here is the Fiddle for that http://sqlfiddle.com/#!9/eb0fd/65 ...
GL!
P. S. sorry for my English hope you could understand what i was talking about...
I've tried a few of the similar SO questions, but I can't seem to figure it out.
On the first inner join, I only want to bring in DISTINCT function columns code and serial_id. So when I do my SUM selects, it calculates one per distinct. Ie there are multiple rows with the same func.code and func.serial_id. I only want 1 of them.
SELECT
sl.imp_id,
lat.version,
SUM(IF(lat.status = 'P',1,0)) AS powered,
SUM(IF(lat.status = 'F',1,0)) AS functional
FROM slots sl
INNER JOIN functions func ON sl.id = func.slot_id
INNER JOIN latest_status lat ON lat.code = func.code
AND lat.serial_id = func.serial_id
WHERE sl.id=55
GROUP BY sl.imp_id, lat.version
EDIT 2 - sample data explanation -------------------
slots - id, imp_id, name
functions - id, slot_id, code, serial_id
latest_status - id, code, serial_id, version, status
**slots**
id imp_id name
1 5 'the name'
2 5 'another name'
3 5 'name!'
4 5 'name!!'
5 5 'name!!!'
6 5 'testing'
7 5 'hi'
8 5 'test'
**functions**
id slot_id code serial_id
1 1 11HRK 10
2 2 22RMJ 11
3 3 26OLL 01
4 4 22RMJ 00
6 6 11HRK 10
7 7 11HRK 10
8 8 22RMJ 00
**latest_status**
id code serial_id version status
1 11HRK 10 1 F
1 11HRK 10 2 P
3 22RMJ 11 1 P
4 22RMJ 11 2 F
5 26OLL 01 1 F
6 26OLL 01 2 P
7 22RMJ 00 1 F
8 22RMJ 00 2 F
After running the query, the result should look like this:
imp_id version powered functional
5 1 1 3
5 2 2 2
The function table gets rolled up based on the code, serial_id. 1 row per code, serial_id.
It then gets joined onto the latest_status table based on the serial_id and code, which is a one (functions) to many (latest_status) relationship, so two rows come out of this, one for each version.
How about using DISTINCT?
SELECT
SUM(IF(lat.status = 'P',1,0)) AS powered,
SUM(IF(lat.status = 'F',1,0)) AS functional
FROM slots sl
INNER JOIN (Select DISTINCT id1, code, serial_id from functions) f On sl.rid = f.id1
INNER JOIN latest_status lat ON lat.code = f.code
AND lat.serial_id = f.serial_id
WHERE sl.id=55
GROUP BY sl.imp_id, lat.version
If you want only the distinct code and serial_id, you need to group by those not the imp_id and version. And end up with something like
SELECT
SUM(IF(lat.status = 'P',1,0)) AS powered,
SUM(IF(lat.status = 'F',1,0)) AS functional
FROM slots sl
INNER JOIN functions func ON sl.rid = func.id1
INNER JOIN latest_status lat ON lat.code = func.code
AND lat.serial_id = func.serial_id
WHERE sl.id=55
GROUP BY func.code, func.serial_id
However, this could all be rubish, without more data as tgo what some of those other columns are, but they dont seem to be the ones you wanted to group by.