Two mysql counts with two different where conditions in one query - mysql

I have a table with two columns namely teacherid and sub_group. Now, sub_group can have values ranging from 0-100 where 0 means lectures for teachers and anything greater than 0 means tutorials. I want to be able to calculate the number of lectures and tutorials grouped by teachers.
So far i have two queries like
SELECT teacherid, count(*) as lectures FROM `ttresponsibility` where sub_group = 0
group by teacherid
SELECT teacherid, count(*) as tutorials FROM `ttresponsibility` where sub_group > 0
group by teacherid
I want to combine the results of the two into one resultset, something like
teacher lectures tutorials
1 15 10
2 14 8
Please suggest...

You can use the aggregate function with a CASE expression:
select teacherid,
sum(case when sub_group = 0 then 1 else 0 end) lectures,
sum(case when sub_group > 0 then 1 else 0 end) tutorials
from `ttresponsibility`
group by teacherid;
This will give you 3 columns, the teacherId and then the total lectured and tutorials in separate columns.

This relies on COUNT ignoring NULLs (the missing ELSE in the CASE expression)
SELECT
teacherid,
count(CASE WHEN sub_group = 0 THEN 1 END) as lectures
count(CASE WHEN sub_group > 0 THEN 1 END) as tutorials
FROM
`ttresponsibility`
group by teacherid

You can use CASE statement to get what you want here.
SELECT
teacherid,
SUM(CASE WHEN sub_group = 0 THEN 1 ELSE 0 END CASE) as lectures,
SUM(CASE WHEN sub_group > 0 THEN 1 ELSE 0 END CASE) as tutorials,
FROM ttresponsibility
GROUP BY teacherid

Almost same solution, as other guys offered, but with IF function:
SELECT
teacherid,
SUM(IF(sub_group = 0, 1, 0)) as lectures,
SUM(IF(sub_group > 0, 1, 0)) as tutorials,
FROM ttresponsibility
GROUP BY teacherid
For me it's easier to read

Related

Count is displaying one only row despite multiple rows in database

Here is my SQL query:
SELECT
COUNT(CASE WHEN `urgency`='1' THEN 1 END) AS verylow,
COUNT(CASE WHEN `urgency`='2' THEN 1 END) AS low,
COUNT(CASE WHEN `urgency`='3' THEN 1 END) AS standard,
COUNT(CASE WHEN `urgency`='4' THEN 1 END) AS high,
COUNT(CASE WHEN `urgency`='5' THEN 1 END) AS critical,
tbl_users.userName
FROM
notes, tbl_users
WHERE
notes.responsible = tbl_users.userID
AND project_id = '4413'
AND (notes.status = 'Ongoing' OR notes.status = 'Not started')
and the output is:
verylow low standard high critical userName
5 1 2 1 1 Nick
However this is wrong because i have multiple users in the database who have assigned tasks. and it looks like this in my database:
urgency userName
3 Nick
5 Nick
4 Nick
3 James
1 James
1 Nick
2 Nick
1 James
1 Nick
1 Nick
Any idea why it doesn't count the urgency for the other user and how many different urgencies he has?
What you are doing is not entirely correct. If you would turn on MySQL mode ONLY_FULL_GROUP_BY, you'd get a warning, because you are selecting a column that is not in the GROUP BY clause without applying an aggregation function. So you need a GROUP BY clause.
The entire query should look like so:
SELECT
COUNT(CASE WHEN `urgency`='1' THEN 1 END) AS verylow,
COUNT(CASE WHEN `urgency`='2' THEN 1 END) AS low,
COUNT(CASE WHEN `urgency`='3' THEN 1 END) AS standard,
COUNT(CASE WHEN `urgency`='4' THEN 1 END) AS high,
COUNT(CASE WHEN `urgency`='5' THEN 1 END) AS critical,
tbl_users.userName
FROM
notes, tbl_users
WHERE
notes.responsible = tbl_users.userID
AND project_id = '4413'
AND (notes.status = 'Ongoing' OR notes.status = 'Not started')
GROUP BY tbl_users.userName;
With COUNT you aggregate your rows. As there is no GROUP BY clause, you aggregate them to one row (rather than, say a row per user).
You are selecting userName. Which? As you select only one row, the DBMS picks one arbitrarily.

Obtaining 2 Different results from same column different WHERE in a single query

SELECT COUNT(NAME) AS NAMEA
FROM (DATA.1 WHERE MARKS > 50), COUNT(NAME) AS NAMEB FROM DATA.1
After running it I get this
Syntax error in JOIN operation
I am trying to get the percentage of student pass, no. of student pass, total no. of student and no. of student fail.
Please help me to find whats wrong in the above Query.
please help me.
Thanks
You're essentially running two queries in one.
Query 1:
SELECT COUNT(NAME) AS NAMEA
FROM DATA1
WHERE MARKS > 50
Query 2:
SELECT COUNT(NAME) AS NAMEB
FROM DATA1
If you want both columns in the same query then you would have to use a SUM of a CASE WHEN for the first query.
SELECT SUM(CASE WHEN MARKS > 50 THEN 1 ELSE 0 END) AS NAMEA,
COUNT(NAME) AS NAMEB
FROM DATA1
For the rest of your points you would need the query:
SELECT COUNT(NAME) AS TOTAL_STUDENTS,
SUM(CASE WHEN MARKS > 50 THEN 1 ELSE 0 END) AS STUDENTS_PASSED,
SUM(CASE WHEN MARKS > 50 THEN 1 ELSE 0 END)/COUNT(NAME) AS PASS_RATE,
SUM(CASE WHEN MARKS < 50 THEN 1 ELSE 0 END) AS STUDENTS_FAILED
FROM DATA1
Bear in mind that this missed out students that have exactly 50 marks. If 50 is a pass then you would need to use >= 50 for STUDENTS_PASSED. If 50 is a fail then you would need to use <= 50 for STUDENTS_FAILED.

Convert table of individual events-distances into a summary table of events

Two weeks ago I started learning SQL and it has been going pretty good so far but I have run into a situation that I can't seem to resolve. After two days of searching the web and looking at books, I am no closer to solving this issue, so time to ask for some help. Part of my problem is that being so new to SQL I'm not exactly sure what to search for.
This is using mySQL and INNODB.
After some joins and other things I have the table below with athlete information giving the type of event in which the athlete participated and the distance of that event. The possible event/distance combinations are {A10,A15,B10,B15}.
Events Table
last_name first_name event distance
Munster Eddie A 10
Brady Marsha A 10
Clampet Jethro B 15
Grumby Jonas A 15
Brady Peter A 10
Brady Marsha A 10
Brady Marsha B 15
Grant Ginger B 15
Munster Eddie B 10
Brady Marsha A 10
What I am trying to do as the final step is to transform this table into a form that shows how many times each athlete participated in each event, like the following output:
last_name first_name A10 A15 B10 B15
Munster Eddie 1 0 1 0
Brady Marsha 3 0 0 1
Clampet Jethro 0 0 0 1
Grumby Jonas 0 1 0 0
Brady Peter 1 0 0 0
Grant Ginger 0 0 0 1
I think I want to use correlated subqueries, so I have tried a number variants of this following SQL query but it returns "Operand should contain 1 column(s)", which makes sense.
SELECT last_name, first_name,
count(if(event='A',1,0) AND if(distance=10,1,0)) AS A10
FROM sample s
WHERE (SELECT last_name, first_name, event, distance
FROM sample s1
WHERE s1.last_name = s.last_name
)
ORDER BY last_name, first_name;
The steps I see I need are:
1. create a set of each name in the table, which I can do, and then
2. iterate through each name, creating a new query selecting event/distance and then
3. summing that query on event/distance combination;
4. return the result back up to #1.
I see that procedures provide some looping capabilities, is that the way to do this? Is what I want to do possible in the SQL environment? My next step is to just dump the raw table to PHP and process it there.
Any thoughts and/or solutions are greatly appreciated.
Add GROUP BY:
SELECT last_name,
first_name,
count(if(event = 'A', 1, NULL)
AND if(distance = 10, 1, NULL)) AS A10,
count(if(event = 'A', 1, NULL)
AND if(distance = 15, 1, NULL)) AS A15,
count(if(event = 'B', 1, NULL)
AND if(distance = 10, 1, NULL)) AS B10,
count(if(event = 'B', 1, NULL)
AND if(distance = 15, 1, NULL)) AS B15
FROM sample s
GROUP BY last_name,
first_name
ORDER BY last_name,
first_name;
I would suggest using the SUM + CASE syntax.
Try something like this:
SELECT LAST_NAME,
FIRST_NAME,
SUM(CASE
WHEN EVENT = 'A'
AND DISTANCE = 10 THEN 1
ELSE 0
END) AS A10,
SUM(CASE
WHEN EVENT = 'A'
AND DISTANCE = 15 THEN 1
ELSE 0
END) AS A15,
SUM(CASE
WHEN EVENT = 'B'
AND DISTANCE = 10 THEN 1
ELSE 0
END) AS B10,
SUM(CASE
WHEN EVENT = 'B'
AND DISTANCE = 15 THEN 1
ELSE 0
END) AS B15
FROM SAMPLE
GROUP BY LAST_NAME,
FIRST_NAME
You can find a working example on SQL Fiddle.
Good Luck!

How to optimize this in MySQL?

I have table structure as displayed in first table.
And want to fetch Both Male and Female Counts in a single query so that request will go only for one time onto the server.
This is what you need to do:
select gender,
count(case when age between 0 and 20 then 1 else null end) Age_0_20,
count(case when age between 21 and 40 then 1 else null end) Age_21_40
from yourtable
group by gender
Adjust accordingly :)
Update, with clarifications
Note that COUNT aggregate function only counts non-null values. Thus, the else values in the case must be NULL. The When value returns 1 but it could just be any non-null value.
Some people implement this by using SUM:
select gender,
sum(case when age between 0 and 20 then 1 else 0 end) Age_0_20,
sum(case when age between 21 and 40 then 1 else 0 end) Age_21_40
from yourtable
group by gender
The result is going to be absolutely the same.

SQL query to group records under separate fields

I'm working with MySQL, and I have the following schema:
id school round score win loss tie
2 My School Name 1 10 1 0 0
3 My School Name 2 20 0 1 0
4 My School Name 3 30 1 0 0
5 My School Name 4 40 1 0 0
6 My School Name 5 50 1 0 0
7 My School Name 6 60 0 0 1
And I need the following output, grouped by school name
School Round1 Round2 Round3 Round4 Round5 Round6 wins losses ties
My School Name 10 20 30 40 50 60 4 1 1
So far I feel like I can use GROUP BY School and SUM(win) as wins to get most of the functionality out of it. The hard part, though, is to get those Round_ fields.
Does anyone know how to do this? Thanks in advance, any help would be much appreciated!
Edit: to clarify, I know I have 10 rounds exactly.
We can use a SELECT statement with a GROUP BY school to create a record for each school. The ties, wins, and losses columns are readily calculated with the SUM aggregate function, as you noted. To target a specific round, we can use some clever math (to avoid verbose conditional statements like the one CodeByMoonlight suggested):
If we want to target round R, we note that "round-R" is 0 only when round == R, otherwise it isn't 0. When we take the NOT of "round-R", 0 gets inverted to 1, while everything else gets set to 0. Now, if we multiply !(round-R) by the score of that round, it will give us 0 when the round is not R (as 0*score = 0) and it will give us "score" when the round is R (as 1*score = score). Next, when we take the SUM of this value over the columns, we add score when round=R and 0 otherwise, effectively giving us just the round R score.
Putting that all together gives:
SELECT school AS `School`,
SUM(!(round-1)*score) AS `Round1`,
SUM(!(round-2)*score) AS `Round2`,
SUM(!(round-3)*score) AS `Round3`,
SUM(!(round-4)*score) AS `Round4`,
SUM(!(round-5)*score) AS `Round5`,
SUM(!(round-6)*score) AS `Round6`,
SUM(!(round-7)*score) AS `Round7`,
SUM(!(round-8)*score) AS `Round8`,
SUM(!(round-9)*score) AS `Round9`,
SUM(!(round-10)*score) AS `Round10`,
SUM(win) AS `wins`,
SUM(loss) AS `losses`,
SUM(tie) AS `ties`
FROM `RoundScores` GROUP BY `school`
where RoundScores is the table in question.
EDIT:
If we do not want to manually add 10, we can use prepared statements :
# Store all the conditionals in a string:
# I was not able to to have round loop from 1 to 10, so I iterated over
# all distinct values of 'round' present in the table.
SET #s = "";
SELECT `round`, (#s := CONCAT( #s , "SUM(!(round-",round, ")*score) AS `Round",round, "`," )) FROM `RoundScores` GROUP BY `round`;
# Combine the conditionals from before with the rest of the statement needed.
SET #qry = CONCAT("SELECT school AS `School`,",#s,"SUM(win) AS `wins`,SUM(loss) AS `losses` FROM `RoundScores` GROUP BY `school`");
# Prepare and execute the statement.
PREPARE stmt1 FROM #qry;
EXECUTE stmt1;
TRY WITH UNION ( not tested)
SELECT SUM(win) AS wins, SUM(loss) AS losses, SUM(tie) AS ties
FROM table
GROUP BY (school)
UNION
SELECT score AS round1 FROM table WHERE round=1
UNION
SELECT score AS round2 FROM table WHERE round=2
.... AND so on..
SELECT School, Sum(Case
When Round = 1 Then Score
Else 0
End) AS Round1, Sum(Case
When Round = 2 Then Score
Else 0
End) AS Round2, Sum(Case
When Round = 3 Then Score
Else 0
End) AS Round3, Sum(Case
When Round = 4 Then Score
Else 0
End) AS Round4, Sum(Case
When Round = 5 Then Score
Else 0
End) AS Round5, Sum(Case
When Round = 6 Then Score
Else 0
End) AS Round6, Sum(Case
When Round = 7 Then Score
Else 0
End) AS Round7, Sum(Case
When Round = 8 Then Score
Else 0
End) AS Round8, Sum(Case
When Round = 9 Then Score
Else 0
End) AS Round9, Sum(Case
When Round = 10 Then Score
Else 0
End) AS Round10, Sum(Wins) AS Wins, Sum(Losses) AS Losses, Sum(Ties) AS Ties
FROM MyTable
GROUP BY School
Should work :)