SQL:从类别中获取产品,但也必须在另一组类别中

Tho*_*ana 5 mysql left-join group-concat relational-division

我目前陷入困境.情景是这样的.我的产品可能与多个类别相关联.数据结构如下所示:

Products Table:
product_id  name 
1           Lemon
2           Kiwis
3           Cheese
Run Code Online (Sandbox Code Playgroud)

产品到类别表

product_id   category_id
1            1
1            2
1            3
2            1
2            3
3            2
3            4
Run Code Online (Sandbox Code Playgroud)

类别表(在查询中不需要,但是在此处添加它以帮助可视化正在发生的事情)

category_id  name
1            Fruit
2            Yellow
3            Round
4            Dairy
Run Code Online (Sandbox Code Playgroud)

我在这里苦苦挣扎的是,最初我想要获得所有水果类别的产品(类别ID 1),但我也想检查水果是否是黄色的.请记住,黄色不会是唯一的过滤器,有时我会想要返回黄色和橙色的水果,但是因为奶酪是黄色的,所以它不能归还,因为它不是水果.然而,为了让事情变得更容易,我总是知道我将把水果类作为基础.

数据库结构不能像opencart数据库结构那样改变.

以下是我的尝试:

SELECT GROUP_CONCAT(DISTINCT p2c2.category_id SEPARATOR ',') as categories 
FROM oc_product_to_category p2c 
LEFT JOIN oc_product p ON (p.product_id = p2c.product_id) 
LEFT JOIN oc_product_to_category p2c2 ON (p.product_id = p2c2.product_id) 
WHERE p2c.category_id IN ('1','2')
Run Code Online (Sandbox Code Playgroud)

这种作品除了它将返回奶酪的事实.

注意:我使用Group Concat,因为在所有这一切的最后,我的目标是返回与这些类别匹配的产品,但根据过滤器,我想从符合此条件的产品中返回另一个类别列表.所以:

场景:

获取符合类别标准的产品返回这些产品的类别.

任何帮助将不胜感激.

Bil*_*win 6

这种类型的问题称为关系分裂.

有两种常见的解决方案:

  1. 第一个解决方案将匹配类别组合在一起并与固定字符串进行比较

    SELECT p2c.product_id
    FROM oc_product_to_category p2c
    GROUP BY p2c.product_id
    HAVING GROUP_CONCAT(p2c.category_id SEPARATOR ',' ORDER BY p2c.category_id) = '1,2'
    
    Run Code Online (Sandbox Code Playgroud)
  2. 第二个解决方案JOIN针对每个所需值执行:

    SELECT p.product_id 
    FROM oc_product p 
    INNER JOIN oc_product_to_category p2c1 
      ON (p.product_id = p2c1.product_id AND p2c1.category_id = 1) 
    INNER JOIN oc_product_to_category p2c2 
      ON (p.product_id = p2c2.product_id AND p2c2.category_id = 2) 
    
    Run Code Online (Sandbox Code Playgroud)

我在演示文稿SQL Query Patterns,Optimized中介绍了这些解决方案.我在测试中发现,连接解决方​​案的性能要好得多.


@ Tom的建议是正确的,这是完整查询中的样子:

    SELECT p.product_id, GROUP_CONCAT(p2c3.category_id SEPARATOR ',') AS categories
    FROM oc_product p 
    INNER JOIN oc_product_to_category p2c1 
      ON (p.product_id = p2c1.product_id AND p2c1.category_id = 1) 
    INNER JOIN oc_product_to_category p2c2 
      ON (p.product_id = p2c2.product_id AND p2c2.category_id = 2) 
    INNER JOIN oc_product_to_category p2c3
      ON (p.product_id = p2c3.product_id)
    GROUP BY p.product_id;
Run Code Online (Sandbox Code Playgroud)

DISTINCT那@汤姆建议不应该是必要的,因为你的P2C表应该有超过(产品,CATEGORY_ID)的唯一约束.

  • 如果我是你,我将采用Bill的第二个解决方案,在oc_product_to_category表中添加一个单独的连接,然后将select更改为查询中的内容:`SELECT GROUP_CONCAT(DISTINCT p2c.category_id SEPARATOR',')作为类别`. (2认同)