SQL选择存在子集的所有行

时间:2011-12-08 01:59:48

标签: sql database postgresql relational-division

我确信这个问题有一个答案,但请耐心等待我,因为我是SQL新手,不知道如何提问。

我有这样的数据(这只是简单的简写)。  这是一个postgres db。

table1
id    value
1     111
1     112
1     113
2     111
2     112
2     116
3     111
3     122
3     123
4     126
5     123
5     125
6     111
6     112
6     116

table2
value
111
112
116

我需要返回table1的id,其中table2中的所有值都存在于table1的值中。因此,对于此示例,我的查询将返回2和6。

有没有办法在SQL中执行此操作?或者你可以引导我到一个允许我得到这个结果的数据结构吗?我可以更改任一表的结构,以满足获得此结果的最终需要

非常感谢你。对此的答案是节省生命。

4 个答案:

答案 0 :(得分:6)

考虑一下这个演示:

CREATE TEMP TABLE table1(id int, value int);
INSERT INTO table1 VALUES
 (1,111),(1,112),(1,113)
,(2,111),(2,112),(2,116)
,(3,111),(3,122),(3,123)
,(4,126)
,(5,123),(5,125)
,(6,111),(6,112),(6,116);

CREATE TEMP TABLE table2(value int);
INSERT INTO table2 VALUES
 (111)
,(112)
,(116);

SELECT t1.id
FROM   table1 t1
JOIN   table2 t2 USING (value)
GROUP  BY t1.id
HAVING count(*) = (SELECT count(*) FROM table2)
ORDER  BY t1.id;

结果:

id
-----
2
6

返回table1出现的所有ID,其中table2提供的所有值均为。{ 适用于两个表中的任意行数。

如果table1中出现重复的行,请执行以下操作:

HAVING count(DISTINCT value) = (SELECT count(*) FROM table2) 

答案 1 :(得分:3)

在我看来,你想知道如何提出正确的问题。这里的魔术词是“关系分裂”。

它是Coddrelational algebra中的运算符之一,自此以后提出了一些变体。最近,Chris Date建议用image relations替换整个概念。

SQL没有明确的除法运算符。有许多使用其他运算符的变通方法,最合适的将取决于您的要求,包括对余数的精确除法或除法以及如何处理空除数。然后有通常的考虑因素:SQL产品和版本,性能,个人风格和品味等。

以下是一些可以帮助您做出这些选择的文章:

On Making Relational Division Comprehensible

Divided We Stand: The SQL of Relational Division

答案 2 :(得分:1)

更新另一种可能性:

SELECT t1.id
FROM (SELECT t1.id, t1.value
      FROM table1 t1
      JOIN  table2 t2 USING (value)
      GROUP BY t1.id, t1.value
      ORDER BY t1.id) t1
GROUP BY t1.id      
HAVING COUNT(*) = (SELECT COUNT(*) FROM table2)

如果您使用 EXPLAIN ANALYZE ,我的答案费用总是893-900,即使重复行也是如此。

答案 3 :(得分:0)

NOT EXISTS(... NOT EXISTS)是关系部门的标准解决方案:

SELECT DISTINCT id
FROM table1 t1
WHERE NOT EXISTS (
        SELECT * FROM table2 t2
        WHERE NOT EXISTS (
                SELECT * FROM table1 t1x
                WHERE t1x.value = t2.value
                AND t1x.id = t1.id
                )
        )
        ;

在这种情况下,需要DISTINCT,因为我们无法访问带有id表,只能访问联结t1引用它。