Reputation: 4264
I have a SELECT statement for a list of students at a school, It currently runs with the below code, however I find it takes a good 1-2 seconds per count, most other simple queries on this database take less than half a second so I think I am doing this quite inefficiently here. Is there a better way to do this? 1-2 seconds might not sound like much but in a more detailed statement I add to the below to also count subjects present/absent etc so when I have everything included in the statement it is taking close to 30 seconds to run.
SELECT studentID AS sID, stu.name AS Name,
(
SELECT COUNT( * )
FROM attendance
WHERE ((sID = 1)
AND classdate < CURDATE( ))
) AS present,
(
SELECT COUNT( * )
FROM attendance
WHERE ((sID != 1)
AND classdate < CURDATE( ))
) AS absent
FROM attendance
INNER JOIN students AS stu ON attendance.studentID = stu.id
WHERE awayid != -1
GROUP BY sID
ORDER BY present ASC
---------------------------------------------
| sID | Name | present | absent |
| 1 | John | 28 | 2 |
| 2 | Richard | 26 | 4 |
| 3 | Harry | 22 | 8 |
| 4 | Sarah | 22 | 8 |
| 5 | Tanya | 20 | 10 |
| 6 | Nathan | 20 | 10 |
| 7 | Kate | 20 | 10 |
---------------------------------------------
Upvotes: 0
Views: 213
Reputation: 424983
Making a few assumptions, try this:
SELECT
studentID AS sID,
stu.name AS Name,
sum(a.sID = 1) as present,
sum(a.sID != 1) as absent
FROM students AS stu
JOIN attendance a ON a.studentID = stu.id
AND classdate < CURDATE( )
WHERE awayid != -1
GROUP BY 1, 2
ORDER BY present ASC
Note that in mysql true is 1
and false is 0
, so SUM(condition)
counts how many times it's true, thus avoiding the cumbersome use of CASE
which wold be required by other databases.
Upvotes: 1
Reputation: 1269543
You can use conditional aggregation:
select studentID as sID, stu.name,
sum((sID = 1) AND classdate < CURDATE( )) as present,
sum((sID != 1) AND classdate < CURDATE( )) as absent
FROM attendance INNER JOIN
students AS stu
ON attendance.studentID = stu.id
WHERE awayid != -1
GROUP BY sID
ORDER BY present ASC;
What confuses me, though, is the use of sID
in the subquery. It would not refer to the studentId
in the outer select
. I suspect that another variable should be used there. (And, if there is an sid
in attendance
, why are you calling studentID
sID
in the outer query?)
Upvotes: 1