SQL Count unique rows where a column contains two different values - sql

I have taken a good look around and not been able to find any questions that match mine. Maybe I am not using the right language when searching or whatever, but here goes.
I have an SQL table called Classes that looks something like this
Student_Name | Class
--------------------
Edgar | Chemistry
Allan | Chemistry
Burt | Chemistry
Edgar | Math
Sue | Math
Hamilton | Math
Edgar | English
Sue | English
Edgar | German
Ben | German
I want to count how many students are taking both Math and German.
Assuming the following in this example:
- Student names are unique
- One student can have many classes
Logically I would use a select statement to get a result set of students who are taking Math. Then I would go through each Student_Name from the result set and check them against the table to see how many are taking German.
In this case I would expect a return of 1 as only Edgar is taking both Math and German.
Here are some of the queries I have tried so far to no avail :-(
This one was after doing some research on DISTINCT:
SELECT COUNT(DISTINCT Student_Name) FROM Classes WHERE Class = 'Math' AND Class = 'German';
And this one was after finding out more about GROUP BY:
SELECT COUNT(*) FROM (
SELECT DISTINCT Student_Name FROM Classes
WHERE Class IN ( 'Math', 'German' )
GROUP BY Student_Name
);
Neither of these came out quite right any help would be highly appreciated.

SELECT COUNT(*) totalStudent
FROM
(
SELECT student_name
FROM Classes
WHERE class IN ('Math','German')
GROUP BY student_name
HAVING COUNT(*) = 2
) subAlias
SQLFiddle Demo
OUTPUT
╔══════════════╗
║ TOTALSTUDENT ║
╠══════════════╣
║ 1 ║
╚══════════════╝

Could also do the following:
select count(distinct a.Student_name)
from Classes a inner join Classes b on
a.Class = 'German' and
b.Class = 'Math' and
a.Student_Name = b.Student_name;
This solves the problem where the table contains duplicate rows (as pointed out by a commenter to another answer)

Related

SQL selecting where A equals both B and C

name | course
Jay | LAWS0001
Mark | LAWS0002
Sam | LAWS0002
Alice | LAWS0001
Ryan | LAWS0001
Ryan | LAWS0002
Hey guys, I've got this database and I want to only select the names that take both 'LAWS0001' and 'LAWS0002'. So from this example, it should select 'Ryan' because he's the only person to take both courses.
I tried IN operator:
SELECT name
FROM student
WHERE course IN ('LAWS0001', 'LAWS0002')
but this takes everyone because everyone is taking either of the courses.
Is there an operator for my problem?
You can use your existing query, using a GROUP BY clause to COUNT the number of distinct courses each student is taking in the set ('LAWS0001', 'LAWS0002') and only selecting those students where the count is 2:
SELECT name
FROM student
WHERE course IN ('LAWS0001', 'LAWS0002')
GROUP BY name
HAVING COUNT(DISTINCT course) = 2
Demo on SQLFiddle

SQL having trouble getting desired query

Say we have the following relation:
Author(name,title,language)
What I'm trying to accomplish is to make query that lists all the authors and how many books in a particular language they made, and if they made none in that language then display zero.
What I've tried so far is this
select name, count("language") as SomeLanguage
from Author
where "language"='English'
group by name;
Which gives the count of how many books in the specified language they made, but I don't know how to include the other authors that did not write a book in that language.
Example Output:
Name | SomeLanguage
----------------
Bill | 4
Rob | 1
Bob | 0
You want conditional aggregation:
select name,
sum(case when language = 'English' then 1 else 0 end) as SomeLanguage
from Author
group by name;

Selecting more after group-by while using join

At the moment I am busy with two tables, Students and Classes. These two both contain a column project_group, a way to categorize multiple students from one class into smaller groups.
In the Students table there is a column City that states in which town/city students live, from the rows that have been filled there are already several cities occurring multiple times. The code I used to check how many times a city is being showed is this:
SELECT City, count(*)
FROM Students
GROUP BY City
Now the next thing I want to do is show per class in which cities the students live and how many live there, so for example a result like:
A | - | 2
A | New York | 3
A | Los Angeles | 1
B | - | 1
B | Miami | 2
B | Seattle | 1
Students and Classes can join each other on the column project_group but what I'm mostly interested in his using both the GROUP BY mentioned earlier, using the JOIN and also showing the results per class.
Thanks in advance,
KRAD
I'm not sure what the column name is for A and B in your example. I'm assuming Classes.Class in the following:
SELECT
C.Class
, S.City
, COUNT(S.*) AS Count
FROM
Classes AS C INNER JOIN
Students AS S ON C.Project_Group = S.Project_Group
GROUP BY
C.Class
, S.City
I managed to get it working. While doing some tests to see which exact error message it was that I got, I used this and managed to get it working. I now get an overview per class that shows how many people live in which city. This is the code used.
SELECT class_id, city, count(*) AS amount
FROM students, classes
WHERE students.project_group = classes.project_group
GROUP BY class_id, city
ORDER BY class_id

SQL query help needed joining within a table

I have a table called babynames that looks abit like this:
firstname |sex |year |count
Bob |M| 2010| 150
Bob |M| 2009| 100
Bob |M| 2008| 122
Bob |F| 2007| 2
Bob |F| 2001| 1
What I want to do is get a list of all the baby names that are both female and male, so my query needs to pull all the firstname records that have at least two records in the table and are at least one M and one F.
It's getting late and my mind isn't working well tonight. Can anyone suggest a string that might help me achieve this task?
There are several ways to handle this. One would be to to use a COUNT(DISTINCT sex) = 2 in the HAVING clause. Be sure to GROUP BY firstname.
SELECT
firstname
FROM babynames
GROUP BY firstname
HAVING COUNT(DISTINCT sex) = 2
Here's a demo: http://sqlfiddle.com/#!2/5d221/1
Another would an INNER JOIN against 2 aliases of the same table, where one looks for M while the other looks for F. If a name isn't matched by both conditions, the join can't be made and it will get excluded from the output.
SELECT
DISTINCT
m.firstname
FROM
babynames f
INNER JOIN babynames m ON f.firstname = m.firstname
WHERE
f.sex = 'F'
AND m.sex = 'M'
http://sqlfiddle.com/#!2/5d221/3

Selecting values from one column based on a different columns value

Having trouble stating my problem succinctly here, so I'll just give an example.
Let's say I have a DB2 table about Students:
Name Class Grade
Billy J Econ A
Sarah S Maths B
Greg X Computes A-
Billy J Maths D
Greg X Maths C+
And I want to retrieve those students that are in both Econ and Maths, and display the information thusly:
Name Maths Grade Econ Grade
Billy J D A
How in the world can I accomplish this?
This solution will solve the problem for the two classes you named:
SELECT Name, Math.Grade AS MathsGrade, Econ.Grade AS EconGrade
FROM Students Math INNER JOIN Students Econ ON Math.Name = Econ.Name
WHERE Math.Class = 'Maths' AND Econ.Class = 'Econ'
The only thing that this solution doesn't do is include the spaces in your derived column names. You can do that by writing Maths Grade and Econ Grade in whatever characters DB2 uses for identifier quotes.
To be included students must have both a Maths and an Econ grade.
SELECT * from Students
where id in
(SELECT id from Students where Class = 'Econ')
AND id in
(SELECT id from Students where Class = 'Math');