INNER JOIN其中**每个**行必须与WHERE子句匹配?

时间:2015-06-30 20:09:09

标签: sql postgresql left-join exists

以下是我正在尝试做的简化示例。我有两张桌子,A和B.

A          B
-----      -----
id         id
name       a_id
           value

我想只选择A中的行,其中B中所有行的值与where子句匹配。类似的东西:

SELECT * from A INNER JOIN B on B.a_id = A.id WHERE B.value > 2

上述查询的问题是,如果来自B的任何行的值为> 2我将从A获得相应的行,我只想要来自A的行

1。)所有 B 中B.a_id = A.id 的行与WHERE, OR

匹配

2。)B中没有引用A

的行

B基本上是一个过滤器表。

7 个答案:

答案 0 :(得分:7)

SELECT  *
FROM    a
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    b
        WHERE   b.a_id = a.a_id
                AND (b.value <= 2 OR b.value IS NULL)
        )

答案 1 :(得分:2)

这可以解决您的问题:

SELECT *
FROM   a
WHERE  NOT EXISTS (SELECT *
                   FROM   b
                   WHERE  b.a_id = a.id
                   AND    b.value <= 2)

以下是获得此方法的方式。

假设我们有一个通用量词(与EXISTS平行,存在量词),语法如下:

FORALL table WHERE condition1 : condition2

(要读取:FORALL满足条件1的表元素,则条件2为真)

所以你可以用这种方式编写你的查询:

SELECT *
FROM   a
WHERE  FORALL b WHERE b.a_id = a.id : b.value > 2

(注意即使b中没有元素存在且值为a.id,forall也是如此)

然后,我们可以像往常一样,通过双重否定来转换存在主义量词中的通用量词:

SELECT *
FROM   a
WHERE  NOT EXISTS b WHERE b.a_id = a.id : NOT (b.value > 2)

在纯SQL中,这可以写成:

SELECT *
FROM a
WHERE NOT EXISTS (SELECT * 
                  FROM   b 
                  WHERE  b.a_id = a.id
                  AND    (b.value > 2) IS NOT TRUE)          

这种技术在普遍量化的情况下非常方便。

答案 2 :(得分:1)

试试这个

SELECT * FROM A 
LEFT JOIN B ON B.a_id = A.id
WHERE B.value > 2 OR B.a_id IS NULL

答案 3 :(得分:1)

SELECT * FROM A LEFT JOIN B ON b.a_id = a.id
WHERE B.a_id IS NULL OR NOT EXIST (
        SELECT  1
        FROM    b
        WHERE  b.value <= 2) 

答案 4 :(得分:1)

回答这个问题(看起来你真的要问):

返回A中的所有行,其中BB.a_id = A.id的所有行也通过了测试B.value > 2

相当于:

返回A中的所有行,其中BB.a_id = A.id的行未通过测试B.value > 2

SELECT a.*  --  "rows from A" (so don't include other columns)
FROM   a
LEFT   JOIN b ON b.a_id = a.id
             AND (b.value > 2) IS NOT TRUE -- safe inversion of logic
WHERE  b.a_id IS NULL;

当反转WHERE条件时,请仔细考虑NULL。 IS NOT TRUE是完全反转WHERE条件的简单且安全的方式。替代方案是(b.value <= 2 OR b.value IS NULL),它更长但可能更快(更容易支持索引)。

答案 5 :(得分:0)

SELECT a.is, a.name, c.id as B_id, c.value from A 
INNER JOIN (Select b.id, b.a_id, b.value from B WHERE B.value > 2) C
on C.a_id = A.id 

注意使用select *是一种不好的做法。你只需指定所需的字段。在这种情况下,我可能会删除b.Id引用,因为它们可能不需要。如果您有加入,您有100%的可能会浪费资源发送您不需要的数据,因为重复加入字段。这就是为什么我没有在最终结果集中包含a_id。

答案 6 :(得分:0)

如果您不想使用EXISTS,则可以使用外部联接。

SELECT A.* 
FROM 
    A 
    LEFT JOIN B ON 
        B.a_id = A.id 
        AND B.value <= 2 -- note: condition reversed!!
WHERE B.id IS NULL

这可以通过在B中搜索失败记录的存在来实现。如果找到一个,则连接将匹配,最后的WHERE子句将排除该记录。