INNER JOIN where **every** row must match the WHERE clause?
INNER JOIN where **every** row must match the WHERE clause?
这是我正在尝试做的一个简化示例。我有两个 table,A 和 B。
A B
----- -----
id id
name a_id
value
我只想 select 仅 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,或
2.) B 中没有引用 A 的行
B 基本上是一个 table 过滤器。
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)
)
试试这个
SELECT * FROM A
LEFT JOIN B ON B.a_id = A.id
WHERE B.value > 2 OR B.a_id IS NULL
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)
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。
这应该可以解决您的问题:
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 table中满足条件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)
这种技术在通用量化的情况下非常方便。
如果您不想使用 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
子句将排除该记录。
回答这个问题(你似乎真的想问):
Return 来自 A
的所有行,其中 B
和 B.a_id = A.id
中的所有行也通过了测试 B.value > 2
。
相当于:
Return 来自 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
条件时,请仔细考虑 NULL。 IS NOT TRUE
是 简单而安全的方法 来完美地反转 WHERE
条件。替代方案是 (b.value <= 2 OR b.value IS NULL)
,它更长但可能更快(更容易支持索引)。
- Select rows which are not present in other table
这是我正在尝试做的一个简化示例。我有两个 table,A 和 B。
A B
----- -----
id id
name a_id
value
我只想 select 仅 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,或
2.) B 中没有引用 A 的行
B 基本上是一个 table 过滤器。
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)
)
试试这个
SELECT * FROM A
LEFT JOIN B ON B.a_id = A.id
WHERE B.value > 2 OR B.a_id IS NULL
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)
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。
这应该可以解决您的问题:
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 table中满足条件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)
这种技术在通用量化的情况下非常方便。
如果您不想使用 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
子句将排除该记录。
回答这个问题(你似乎真的想问):
Return 来自 A
的所有行,其中 B
和 B.a_id = A.id
中的所有行也通过了测试 B.value > 2
。
相当于:
Return 来自 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
条件时,请仔细考虑 NULL。 IS NOT TRUE
是 简单而安全的方法 来完美地反转 WHERE
条件。替代方案是 (b.value <= 2 OR b.value IS NULL)
,它更长但可能更快(更容易支持索引)。
- Select rows which are not present in other table