想象一下下面的表格:
创建表格框(id int,name text,...);
创建表thinginboxes(id int,box_id int,thing enum('apple,'banana','orange');
表格如下:
Boxes: id | name 1 | orangesOnly 2 | orangesOnly2 3 | orangesBananas 4 | misc thingsinboxes: id | box_id | thing 1 | 1 | orange 2 | 1 | orange 3 | 2 | orange 4 | 3 | orange 5 | 3 | banana 6 | 4 | orange 7 | 4 | apple 8 | 4 | banana
如何选择至少包含一个橙色且不包含任何橙色的框?
假设我有数十万个盒子,可能有一百万个盒子里的东西,这个规模如何?
如果可能的话,我想将这一切保留在SQL中,而不是使用脚本对结果集进行后处理。
我正在使用postgres和mysql,所以子查询可能不好,因为mysql不优化子查询(无论如何都是版本6)。
答案 0 :(得分:5)
SELECT b.*
FROM boxes b JOIN thingsinboxes t ON (b.id = t.box_id)
GROUP BY b.id
HAVING COUNT(DISTINCT t.thing) = 1 AND SUM(t.thing = 'orange') > 0;
这是另一个不使用GROUP BY的解决方案:
SELECT DISTINCT b.*
FROM boxes b
JOIN thingsinboxes t1
ON (b.id = t1.box_id AND t1.thing = 'orange')
LEFT OUTER JOIN thingsinboxes t2
ON (b.id = t2.box_id AND t2.thing != 'orange')
WHERE t2.box_id IS NULL;
与往常一样,在您对查询的可扩展性或性能做出结论之前,您必须尝试使用实际数据集,并衡量效果。
答案 1 :(得分:2)
我认为Bill Karwin的查询很好,但是如果相对较小比例的盒子包含橙子,你应该能够通过使用thing
字段上的索引加快速度:
SELECT b.*
FROM boxes b JOIN thingsinboxes t1 ON (b.id = t1.box_id)
WHERE t1.thing = 'orange'
AND NOT EXISTS (
SELECT 1
FROM thingsinboxes t2
WHERE t2.box_id = b.id
AND t2.thing <> 'orange'
)
GROUP BY t1.box_id
WHERE NOT EXISTS
子查询只会在每个橙色的东西上运行一次,所以只要橙子不多,它就不会太贵。