Reputation: 9302
In our school, when a student is good, they get given a virtual pound (or dollar) which is stored in a database.
This is my query:
SELECT s.chosen_name, s.chosen_surname, s.regId, s.admission_number,
(
SELECT SUM(a.pounds_amount)
FROM tbl_pounds_log a
WHERE a.student_id=l.student_id
) AS total_pounds,
(
SELECT SUM(b.pounds_amount)
FROM tbl_pounds_log b
WHERE b.student_id=l.student_id
AND b.staff_id=:staffId
AND b.action_timestamp>(UNIX_TIMESTAMP()-3600)
) AS available_pounds
FROM TBL_student s
LEFT JOIN tbl_pounds_log l
ON l.student_id=s.admission_number
WHERE ((s.chosen_name LIKE :termOne AND s.chosen_surname LIKE :termTwo)
OR (s.chosen_name LIKE :termThree AND s.chosen_surname LIKE :termFour))
AND (total_pounds>=:lowerPoundLimit
AND total_pounds<=:upperPoundLimit)
GROUP BY s.admission_number
ORDER BY s.chosen_surname ASC, s.chosen_name ASC
LIMIT 0,10
(I'm using PHP PDO to perform the query hence the :text placeholders).
I'm having a bit of an issue when it comes to the WHERE condition in the parent query.
Where it says:
... AND (total_pounds>=:lowerPoundLimit and total_pounds<=:upperPoundLimit)
The total_pounds field is a column result of a subquery, however when I run the query it keeps coming up with:
Unknown column 'total_pounds' in 'where clause'
Does anyone know a solution to this?
Thanks
Phil
Upvotes: 0
Views: 4609
Reputation: 6315
The problem is that the alias names is not yet available when the WHERE
clause is evaluated. The problem should be solved by moving the subqueries from the SELECT
clause into JOIN
clauses like this:
SELECT s.chosen_name, s.chosen_surname, s.regId, s.admission_number,
total_pounds.pound_amount as total_pounds,
available_pounds.pound_amount as available_pounds
FROM TBL_student s
LEFT JOIN
(SELECT student_id, SUM(pounds_amount) AS pound_amount
FROM tbl_pounds_log
GROUP BY student_id) AS total_pounds
ON total_pounds.student_id = s.admission_number
LEFT JOIN
(SELECT student_id, SUM(b.pounds_amount) AS pound_amount
FROM tbl_pounds_log
WHERE b.staff_id=:staffId
AND b.action_timestamp>(UNIX_TIMESTAMP()-3600)
GROUP BY student_id) as available_pounds
ON available_pounds.student_id = s.admission_number
WHERE ((s.chosen_name LIKE :termOne AND s.chosen_surname LIKE :termTwo)
OR (s.chosen_name LIKE :termThree AND s.chosen_surname LIKE :termFour))
AND (total_pounds.pound_amount >= :lowerPoundLimit
AND total_pounds.pound_amount <= :upperPoundLimit)
GROUP BY s.admission_number
ORDER BY s.chosen_surname ASC, s.chosen_name ASC
LIMIT 0,10
It is also seems possible to write the query without subqueries:
SELECT s.chosen_name, s.chosen_surname, s.regId, s.admission_number,
SUM(tp.pounds_amount) AS total_pounds
SUM(ap.pounds_amount) AS available pounds
FROM tbl_students s
LEFT JOIN tbl_pounds_log tp
ON tp.student_id = s.admission_number
LEFT JOIN tbl_pounds_log ap
ON ap.student_id = tp.student_id
AND ap.staff_id = tp.staff_id
AND ap.staff_id = :staffId
AND ap.action_timestamp = tp.action_timestamp
AND ap.action_timestamp > (UNIX_TIMESTAMP()-3600)
WHERE s.chosen_name LIKE :termOne AND s.chosen_surname LIKE :termTwo
OR s.chosen_name LIKE :termThree AND s.chosen_surname LIKE :termFour
GROUP BY s.admission_number, s.name, s.regId, s.admission_number
HAVING SUM(tp.pounds_amount) BETWEEN upperPoundLimit AND lowerPoundLimit
ORDER BY s.chosen_surname, s.chosen_name
LIMIT 0,10
Upvotes: 3
Reputation: 2206
Trying to avoid subqueries may be the 'real' solution (it may be possible to join tables and GROUP BY results)
Anyway, since you can't refer to 'total_pounds' in the WHERE clause, an easy solution is to repeat the subquery. This is ugly, but maybe query optimizer and/or your server's cache (if enable) will avoid executing 2 times each subquery...
Upvotes: 1