patternsqlMinor
Mysql LEFT JOINing same table twice
Viewed 0 times
leftsametwicemysqltablejoining
Problem
mysql> SELECT * FROM customers;
+----+------+
| id | name |
+----+------+
| 1 | Matt |
| 3 | John |
+----+------+
mysql> SELECT * FROM purchases;
+----------+------+-------+
| owner_id | type | quant |
+----------+------+-------+
| 3 | cat | 3 |
| 3 | cat | 2 |
| 1 | cat | 4 |
| 1 | dog | 1 |
| 1 | dog | 2 |
+----------+------+-------+So i have two tables and want to see a column with a customer name then a column with total number of dogs purchased followed by a column for cats and this is what i came up with
mysql> SELECT c.name, sum(dogs.quant) AS dogs, SUM(cats.quant) AS cats
-> FROM customers AS c
-> LEFT JOIN purchases AS dogs ON c.id=dogs.owner_id AND dogs.type = 'dog'
-> LEFT JOIN purchases AS cats ON c.id=cats.owner_id AND cats.type = 'cat'
-> GROUP BY c.name;
+------+------+------+
| name | dogs | cats |
+------+------+------+
| John | NULL | 5 |
| Matt | 3 | 8 |
+------+------+------+Can someone explain why Matt has 8 cats when i expect it to be 4? This is a boiled down version of my problem
Solution
Perhaps it is easiest to see why this is happening by removing the aggregate functions:
You get a "multiplier effect" since you are joining the purchase table twice. Here's an alternative solution:
SELECT c.name
, dogs.quant
, cats.quant
FROM customers AS c
LEFT JOIN purchases AS dogs
ON c.id=dogs.owner_id
AND dogs.type = 'dog'
LEFT JOIN purchases AS cats
ON c.id=cats.owner_id
AND cats.type = 'cat'
+------+-------+-------+
| name | quant | quant |
+------+-------+-------+
| Matt | 1 | 4 |
| Matt | 2 | 4 |
| John | NULL | 3 |
| John | NULL | 2 |
+------+-------+-------+You get a "multiplier effect" since you are joining the purchase table twice. Here's an alternative solution:
SELECT c.name
, sum(case when type = 'dog' then quant end) AS dogs
, sum(case when type = 'cat' then quant end) AS cats
FROM customers AS c
JOIN purchases p
ON c.id=p.owner_id
GROUP BY c.name;Code Snippets
SELECT c.name
, dogs.quant
, cats.quant
FROM customers AS c
LEFT JOIN purchases AS dogs
ON c.id=dogs.owner_id
AND dogs.type = 'dog'
LEFT JOIN purchases AS cats
ON c.id=cats.owner_id
AND cats.type = 'cat'
+------+-------+-------+
| name | quant | quant |
+------+-------+-------+
| Matt | 1 | 4 |
| Matt | 2 | 4 |
| John | NULL | 3 |
| John | NULL | 2 |
+------+-------+-------+SELECT c.name
, sum(case when type = 'dog' then quant end) AS dogs
, sum(case when type = 'cat' then quant end) AS cats
FROM customers AS c
JOIN purchases p
ON c.id=p.owner_id
GROUP BY c.name;Context
StackExchange Database Administrators Q#71325, answer score: 3
Revisions (0)
No revisions yet.