我有一个 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')
在上面的例子中,我想得到 都 匹配给定数组的项目,所以所有有 绿化或 蓝色或 绿化 和 蓝色 颜色。但 如果一个项目有 蓝色 以及 红色 颜色(或仅 红色或没有颜色),它应该从结果中排除。
目前,我没有找到合适的方法来做。我上面的例子中的查询检索的数据比我预期的要多。谢谢你的帮助
一种方法是使用聚合。
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')
);
如果你正在运行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