o15a3d4l11s2 o15a3d4l11s2 - 3 months ago 19
MySQL Question

Many-to-many combinations

I have the following standard many-to-many relation:
http://sqlfiddle.com/#!9/43bd68/28/0

(simplified version) - I have product 1, which has categories 1, 2, 3 and product 2, which has categories 1, 3.

What I am trying to achieve is to select the products that belong to specific combination of categories.

To illustrate it:


  • Get products that belong to categories (1 or 2) and belong to categories (3). This should return both products 1 and 2

  • Get products that belong to categories (2) and belongs to categories (3). This should return only product 1



The categories should behave like "filters" - that's why my initial thought was to set
WHERE category IN (1, 2) AND category IN (3)
, but this does not work, as the category is a single value for one row. I think I need something like "foreach product and then inside the product check if it has category (1 or 2) and has category(3)".

Is it possible to achieve this with an SQL query?

Answer

You can use a query like the following:

SELECT
  p.name as prodName, p.id as pid
FROM
  Product p
JOIN Category_Product cp ON p.id = cp.product_id
JOIN Category c ON c.id = cp.category_id
WHERE category_id IN (2,3)
GROUP BY pid
HAVING COUNT(*) = 2

Demo here

To implement a query for the first case you have to use a conditional aggregate in HAVING clause:

SELECT
  p.name as prodName, p.id as pid
FROM
  Product p
JOIN Category_Product cp ON p.id = cp.product_id
JOIN Category c ON c.id = cp.category_id
WHERE category_id IN (1,2,3)
GROUP BY pid
HAVING COUNT(CASE WHEN category_id IN (1,2) THEN 1 END) > 0 AND
       COUNT(CASE WHEN category_id = 3 THEN 1 END) >= 1

Demo here