I have query I need to perform in MySQL on three linked tables. I can do it the lazy way with nested queries but I cannot work out how to do it with a single query.
Tables are:
Area:-
: id (int)
: name (string)
Consultant:-
:id (int)
:active (1/0)
ConsArea:-
: areaID (int)
: consultantID (int)
I need to loop through all the areas (with $area
variable) so that I list ALL areas and against each area to indicate the number of 'active' consultants ... so all areas must be listed with a value next to it (which can be zero if there are no active consultants associated)
The first part of the query (irrespective of consultant active or not) I can do with:
SELECT areas.name AS aname, COUNT(consAreas.areaID) AS cct
FROM areas LEFT OUTER JOIN consAreas
ON consAreas.areaID = areas.id
WHERE areas.areaID = $area
GROUP BY areas.id
ORDER BY areas.name
.. but when I want to include the condition of the consultant being active I cannot work out the correct join. It only lists the areas with > 0 active consultants whereas I need all areas.
SELECT areas.name AS aname, COUNT(consAreas.area) AS cct
FROM areas LEFT OUTER JOIN consAreas
ON consAreas.area = areas.id
**JOIN consultants ON consultants.id = consAreas.cons**
WHERE areas.areaID = $area
**AND consultants.active = 1**
GROUP BY areas.id
ORDER BY areas.name
Anyone help?
This is because of a behaviour of mysql. An inner join following a left join makes that left join an inner join.
SELECT areas.name AS aname, COUNT(consultants.id) AS cct
FROM areas
LEFT JOIN consAreas ON consAreas.area = areas.id
LEFT JOIN consultants ON consultants.id = consAreas.cons AND consultants.active = 1
WHERE
areas.areaID = $area
GROUP BY areas.id
ORDER BY areas.name
Here you can see I'm only using left joins, and more importantly filtering the consultants.active
status from the left join ON clause directly.
What you want here is a LEFT JOIN
(aka left outer join).
A JOIN
(really an inner join) selects a row resulting from the JOIN only if it has corresponding rows in both tables. A left join will select rows if only the left table has a matching row, regardless of whether the right one does.
So in your join to the consultants table:
SELECT areas.name AS aname, COUNT(consAreas.area) AS cct
FROM areas LEFT OUTER JOIN consAreas
ON consAreas.area = areas.id
LEFT JOIN consultants ON consultants.id = consAreas.cons
You need to do a LEFT JOIN
and correct the GROUP BY
. Try this:
SELECT areas.name AS aname, COUNT(consultants.active) AS cct
FROM areas
LEFT JOIN consAreas
ON consAreas.area = areas.id
LEFT JOIN consultants
ON consultants.id = consAreas.cons
WHERE areas.areaID = $area
AND consultants.active = 1
GROUP BY areas.name
ORDER BY areas.name
This will return a table with the name of area and the number of active consultants
Try this:
SELECT areas.name AS aname, COUNT(consultants.id) AS cct
FROM areas LEFT OUTER JOIN consAreas
ON consAreas.areaID = areas.id
LEFT OUTER JOIN consultants ON consAreas.consultantID=consultants.id AND consultants.active = 1
WHERE areas.areaID = $area
GROUP BY areas.id
ORDER BY areas.name
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.