MySQL 从数组中有条件地查询多对多关系(内部连接表)
MySQL conditional querying many to many relations (inner joined tables) from an array
我有一个 colors
table 和一个 items
table,它们之间有 多对多 关系2 table 秒(通过 items_colors
table)。一个项目可以有多种颜色,一种颜色可以有很多项目。
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')
在我上面的示例中,我想获得与给定数组匹配的 all 项,因此所有具有 green 的项,或者blue,或 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;
这不是 return 颜色,但你可以 return 那些 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,你可以使用 window 函数进行过滤:
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
我有一个 colors
table 和一个 items
table,它们之间有 多对多 关系2 table 秒(通过 items_colors
table)。一个项目可以有多种颜色,一种颜色可以有很多项目。
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')
在我上面的示例中,我想获得与给定数组匹配的 all 项,因此所有具有 green 的项,或者blue,或 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;
这不是 return 颜色,但你可以 return 那些 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,你可以使用 window 函数进行过滤:
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