简体   繁体   中英

MySQL query with two joins

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM