5

想象以下表格:

创建表格框(id int,名称文本,...);

创建表 thingsinboxes(id int, box_id int, thing enum('apple,'banana','orange');

表格看起来像:

盒子:
编号 | 姓名
1 | 只有橘子
2 | 只有橘子2
3 | 橙子香蕉
4 | 杂项

收件箱:
编号 | box_id | 事物
1 | 1 | 橙
2 | 1 | 橙
3 | 2 | 橙
4 | 3 | 橙
5 | 3 | 香蕉
6 | 4 | 橙
7 | 4 | 苹果
8 | 4 | 香蕉

如何选择至少包含一个橙色且没有不是橙色的框?

假设我有几十万个盒子,而且盒子里可能有一百万个东西,这个规模如何?

如果可能的话,我想把这一切都保存在 SQL 中,而不是用脚本对结果集进行后处理。

我同时使用 postgres 和 mysql,所以子查询可能很糟糕,因为 mysql 不优化子查询(无论如何都是 6 之前的版本)。

4

2 回答 2

6
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;

与往常一样,在对查询的可扩展性或性能做出结论之前,您必须使用真实的数据集进行尝试,并衡量性能。

于 2009-01-26T22:19:54.660 回答
2

thing我认为 Bill Karwin 的查询很好,但是如果相对较小比例的盒子包含橘子,您应该能够通过在字段上使用索引来加快速度:

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东西只会运行一次,所以如果没有很多橘子,它不会太贵。

于 2009-01-26T22:45:05.560 回答