开发者

Forcing all rows from first table of a join

I have three tables, machines holding vending machines, products holding al开发者_开发技巧l possible products, and machines_products which is the intersection of the two, giving how many of each product line is stocked in a particular machine. If a product is not stocked in a machine, there is no corresponding row in the third table.

DESCRIBE machines_products;
+------------+------------------+------+-----+---------+-------+
| Field      | Type             | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| machine_id | int(10) unsigned | NO   | PRI | 0       |       |
| product_id | int(10) unsigned | NO   | PRI | 0       |       |
| quantity   | int(10) unsigned | NO   |     | 0       |       |
+------------+------------------+------+-----+---------+-------+

Each product has a category (think chocolate bars vs. drinks bottles) and a machine knows what category of products it can vend. I want a result table of all products for the category, with a quantity for a specific machine. I have got as far as this:

SELECT products.*, SUM(quantity) qty
FROM products
LEFT JOIN machines_products USING (product_id)
WHERE machine_id=m AND category_id=c
GROUP BY product_id;

The problem is that this filters out all rows where there is no quantity, whereas what I want is all rows from the left table, and NULL/0 in the qty column if there are no corresponding rows in the right-hand table.

BTW: this is not a homework question! I am 30 and sitting in my office :o)


SELECT p.*
     , SUM(mp.quantity) AS qty
FROM products p
  LEFT JOIN machine_products mp
    ON mp.product_id = p.product_id
    AND mp.machine_id = m              --- this condition moved from WHERE to ON
WHERE p.category_id = c
GROUP BY p.product_id


Actually I figured out the answer a short while after posting. The trick is to avoid specifying either of the columns from the third table's primary key (i.e. machine_id and product_id) in the WHERE clause. By using an AND in the JOIN's ON condition, and specifying the machine ID there, I get the result I was looking for.

SELECT products.*, quantity
FROM products
LEFT JOIN machines_products
  ON products.product_id=machines_products.product_id
  AND machine_id=m
WHERE category_id=c

The COALESCE() function suggested by Brendan was not necessary in my case, since I check the value with PHP's empty() function, so NULL is fine.

As it turns out, there was never a need for GROUP BY, which I had been playing with when posting the question.


SUM returns NULL if a single value in the equation is NULL. COALESCE the value first and then SUM:

SELECT p.*, SUM(COALESCE(mp.quantity, 0)) AS qty
FROM products p
LEFT JOIN machine_products mp ON mp.product_id = p.id
WHERE mp.machine_id = m
AND p.category_id = c
GROUP BY p.id

I assumed you have a column in products called id. Rename if it's something different...


SELECT p.id, SUM(mp.quantity) AS qty 
FROM products p 
LEFT JOIN machines_products mp ON p.id=mp.product_id
WHERE mp.machine_id=m 
AND p.category_id=c 
GROUP BY p.id;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜