假设我有三个MySQL表:
╔═════════════════╗ ╔════════════╗ ╔══════════════════════╗
║ animals ║ ║ colors ║ ║ animal_color ║
╠════╦════════════╣ ╠════╦═══════╣ ╠═══════════╦══════════╣
║ id ║ name ║ ║ id ║ name ║ ║ animal_id ║ color_id ║
╠════╬════════════╣ ╠════╬═══════╣ ╠═══════════╬══════════╣
║ 1 ║ Panther ║ ║ 1 ║ black ║ ║ 1 ║ 1 ║
║ 2 ║ Zebra ║ ║ 2 ║ white ║ ║ 2 ║ 1 ║
║ 3 ║ Polar bear ║ ║ 3 ║ blue ║ ║ 2 ║ 2 ║
╚════╩════════════╝ ╚════╩═══════╝ ║ 3 ║ 2 ║
╚═══════════╩══════════╝
每只动物可以分配一种或多种颜色。我如何寻找同时具有黑色和白色颜色(斑马)的动物?我知道有多种方法可以做到,但有哪些简单方法呢?也许没有任何子查询?
我出现了类似的东西:
SELECT *
FROM `animals`
WHERE `id` IN (SELECT `animal_id`
FROM `animal_color`
WHERE `color_id` IN ( 1, 2 )
GROUP BY `animal_id`
HAVING COUNT(*) = 2)
但是我觉得它很笨拙而我也不喜欢我需要计算我感兴趣的颜色数量。
似乎有一些简单的方法可以做到。
更新
了解这个问题的两个版本的简单方法会很棒:
答案 0 :(得分:1)
我不认为你的方法太糟糕了,还有你提到的唯一索引,以确保结果是正确的。
有一个更简单的'没有子查询的版本 - 你可以连接两次动物颜色,一次用于黑色,一次用于白色 - 它会自我过滤,但这种方法不可扩展到覆盖3种颜色的动物查询等,所以我不热衷于它作为一种解决方案。
只要SQL生成的查询计划有效,并且查询的含义明显/可维护,那就足够了。那些应该是SQL语句的目标。
答案 1 :(得分:0)
对于黑白颜色的动物:
SELECT a.name
FROM animals a
INNER JOIN animal_color ac ON (a.id = ac.animal_id)
INNER JOIN colors c ON (ac.color_id = c.id AND c.name IN ('black', 'white'))
GROUP BY a.id
HAVING COUNT(DISTINCT ac.color_id) = 2
话虽如此,你的方法本身并不“不正确”。使用连接过滤实际上可能被认为比where语句内部的可读性差,但是我更喜欢缺少子查询,这是基于意见的,并且两种方法都将在没有性能问题的情况下进行规划。
另请注意,如果您不关心按ID指定颜色,则可以删除连接:
SELECT a.name
FROM animals a
INNER JOIN animal_color ac ON (a.id = ac.animal_id AND ac.color_id IN (1, 2))
GROUP BY a.id
HAVING COUNT(DISTINCT ac.color_id) = 2
答案 2 :(得分:0)
检查动物是否有2种颜色,这些颜色是白色和黑色。
SELECT a.id, a.name
FROM animals a
JOIN animal_color c on c.animal_id = a.id
GROUP a.id, a.name
HAVING Count(color_id) = 2
AND Count(CASE WHEN c.color_id IN (1,2)
THEN 1
END) = 2
答案 3 :(得分:0)
我提出了自己的解决方案。
选择黑色和白色的动物,但也可以有其他颜色:
SELECT *
FROM animals
WHERE (SELECT COUNT(DISTINCT colors.id)
FROM colors
JOIN animal_color
ON animal_color.color_id = colors.id
WHERE animal_color.animal_id = animals.id
AND colors.name IN ( 'black', 'white' )) = 2
选择仅黑色和白色的动物:
SELECT *
FROM animals
WHERE (SELECT GROUP_CONCAT(DISTINCT colors.name ORDER BY colors.name)
FROM colors
JOIN animal_color
ON animal_color.color_id = colors.id
WHERE animal_color.animal_id = animals.id) = 'black,white'
如你所见,我是按颜色获取的,因为它有时会更有用。将其更改为颜色ID很容易。
另外,我可以轻松获取我想要的任何其他数据,因为只能在WHERE
子句中查找动物。
最后,它可以正确使用重复的颜色。获取黑色和白色只需要脚本按字母顺序排序所需的颜色,但它没关系。我对相对简单的查询感到满意。