MySQL从一个数组中有条件地查询多对多关系(内部连接表)。

问题描述 投票:0回答:1

我有一个 colors 桌子和一个 items 桌子,有 屡屡 这两个表之间的关系(通过一个 items_colors 表)。) 一个项目可以有很多颜色,一个颜色可以有很多项目。

items
   id

colors
   id
   name

items_colors
    item_id [foreign key: items(id)]
    color_id [foreign key: colors(id)]

从一个颜色数组中,我想得到所有的项目,这些项目是 唯唯诺诺 一个或多个提供的颜色。如果一个项目还关联了一个没有在数组中指定的附加颜色,那么它就不应该被检索。

SELECT
    `*`
FROM
    `items`
    INNER JOIN `items_colors` ON `items_colors`.`item_id` = `items`.`id`
    INNER JOIN `colors` ON `colors`.`id` = `items_colors`.`color_id`
WHERE
    `colors`.`name` IN('green', 'blue')

在上面的例子中,我想得到 匹配给定数组的项目,所以所有有 绿化蓝色绿化蓝色 颜色。 如果一个项目有 蓝色 以及 红色 颜色(或仅 红色或没有颜色),它应该从结果中排除。

目前,我没有找到合适的方法来做。我上面的例子中的查询检索的数据比我预期的要多。谢谢你的帮助

mysql sql many-to-many
1个回答
2
投票

一种方法是使用聚合。

SELECT i.*
FROM items i JOIN
     items_colors ic
     ON ic.item_id = i.id JOIn
     colors c
     ON c.id = ic.color_id
GROUP BY i.id
HAVING SUM( c.name NOT IN ('green', 'blue') ) = 0;

这并不返回颜色,但你可以用以下方法来返回颜色 GROUP_CONCAT(c.name).

你也可以表达 HAVING 条款更积极。

HAVING COUNT(*) = SUM( c.name IN ('green', 'blue') )

也就是说,使用以下句子可能更有效: NOT EXISTS:

select i.*
from items i
where not exists (select 1
                  from item_colors ic join
                       colors c
                       on ic.color_id = c.id
                  where ic.item_id = i.id and
                        c.name NOT IN ('green', 'blue')
                 );

1
投票

如果你正在运行MySQL 8.0,你可以使用窗口功能进行过滤。

SELECT *
FROM (
    SELECT 
        i.*, 
        c.*, 
        ic.*, 
        SUM(c.name NOT IN ('green', 'blue')) OVER(PARTITION BY i.id) cnt 
    FROM items i
    INNER JOIN items_colors ic ON ic.item_id = i.id
    INNER JOIN colors c ON c.id = ic.color_id
) t
WHERE c.name IN ('green', 'blue') and cnt = 0
© www.soinside.com 2019 - 2024. All rights reserved.