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

问题描述 投票:0回答:7

这是我正在尝试做的事情的简化示例。我有两张桌子,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.) ALL B 中的行对于 B.a_id = A.id 与 WHERE 匹配,OR

2.) B 中没有引用 A 的行

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

sql postgresql left-join exists
7个回答
8
投票
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)
        )

3
投票

回答这个问题(看来你确实想问):

返回

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

相当于:

返回

A
中的所有行,其中
B
中带有
B.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
条件时,请仔细考虑空值。
IS NOT TRUE
是完美反转 WHERE 条件的
简单且安全的方法
。另一种选择是
(b.value <= 2 OR b.value IS NULL)
,它更长但可能更快(更容易支持索引)。


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 也为 true)

然后我们可以像往常一样,用双重否定将全称量词转换为存在量词:

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)          

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


1
投票

试试这个

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

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) 

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 包含在最终结果集中。


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
子句将排除该记录。

© www.soinside.com 2019 - 2024. All rights reserved.