在SQL中,执行OUTER JOIN时WHERE条件会限制结果数吗?
In SQL, when performing an OUTER JOIN does WHERE conditions limit the number of results?
如果我有 2 个表 A 和 B,并执行以下查询:
SELECT * FROM A FULL OUTER JOIN B ON A.pk = B.fk;
我了解结果的数量将是 3 种结果的总和:
- 匹配的组合数(a,b)
- 没有匹配 B 的 A 行数:(a, null)
- 没有匹配 A 的 B 行数:(null, b)
但是如果我在 A 上添加条件,例如:
SELECT * FROM A FULL OUTER JOIN B ON A.pk = B.fk WHERE A.field = value;
与之前的查询相比,第一组结果会发生什么变化?
对于某些行,A 上的条件不满足。那些类型“1”的结果是否会变成形式为 (null,b) 的类型“3”的结果,或者这些结果会从结果中完全丢弃吗?
写查询时,不同的操作部分是按顺序写的:
SELECT->FROM->WHERE->GROUP BY->HAVING->ORDER BY->LIMIT
但查询是按以下顺序进行物理计算的:
FROM->WHERE->GROUP BY->SELECT->HAVING->ORDER BY->LIMIT
因此,在您的 FULL OUTER JOIN
的情况下,当您指定 WHERE
子句时,它会根据连接的 table 的结果评估该子句(通常是临时 table 是为此创建的)。如果您希望行为是 A
中返回的唯一记录与 A.field = value
匹配,您需要先 select 来自 A
的那些记录,然后加入该结果到 B
table:
SELECT *
FROM (SELECT A.pk
FROM A
WHERE A.field = value) A
FULL OUTER JOIN B
ON A.pk = B.fk;
Here 是一个 SqlFiddle 所以你可以看到。
RECAP - 完全外部联接中使用的条件
我已经创建了最简单的场景,其中有 2 个表包含匹配记录和双方不匹配的记录,并测试了所有情况,在此 sqlfiddle 中:http://sqlfiddle.com/#!3/901cd2/11
fiddle 是基于@JRLambert 的回答,我已经接受了他的回答。本回答仅作总结和保管。
这里有SQL个关于这个fiddle的查询和解释(以防有一天它消失):
-- Basic full join
-- Returns (a,b) for matching records, and also (a, null) and (null, b)
-- for all records from A and B without matches
SELECT * FROM A
FULL OUTER JOIN B
ON A.pk = B.fk;
-- With condition in the ON clause
-- Only joins results (a,b) if conditions are satisfied on A.
-- The example returns :
-- 1. (a,b) only if A and B records are matched, and a.field = 0
-- 2. (a, null) for unmatched A records, and also all values of A with A.field != 0 (even if there is a matching B record)
-- 3. (null, b) for all unmatched B records, or with matching A records not satisfying the condition
SELECT * FROM A
FULL OUTER JOIN B
ON A.pk = B.fk AND A.field = 0;
-- With condition in the WHERE clause
-- Joins all matching record first, and return only pairs (a,b) and (a, null) if a satisfied the condition.
-- This example joins as the first "Basic full join", and then only returns rows with a satisfying the condition (meaning cannot be null)
SELECT * FROM A
FULL OUTER JOIN B
ON A.pk = B.fk
WHERE A.field = 0;
-- To select all join results satisfying the condition on A,
-- but keeping all B results as (null,b) whenever the condition is not true on A,
-- preselect keys before the join
SELECT *
FROM (SELECT A.pk FROM A WHERE A.field = 0) A
FULL OUTER JOIN B
ON A.pk = B.fk;
如果我有 2 个表 A 和 B,并执行以下查询:
SELECT * FROM A FULL OUTER JOIN B ON A.pk = B.fk;
我了解结果的数量将是 3 种结果的总和:
- 匹配的组合数(a,b)
- 没有匹配 B 的 A 行数:(a, null)
- 没有匹配 A 的 B 行数:(null, b)
但是如果我在 A 上添加条件,例如:
SELECT * FROM A FULL OUTER JOIN B ON A.pk = B.fk WHERE A.field = value;
与之前的查询相比,第一组结果会发生什么变化?
对于某些行,A 上的条件不满足。那些类型“1”的结果是否会变成形式为 (null,b) 的类型“3”的结果,或者这些结果会从结果中完全丢弃吗?
写查询时,不同的操作部分是按顺序写的:
SELECT->FROM->WHERE->GROUP BY->HAVING->ORDER BY->LIMIT
但查询是按以下顺序进行物理计算的:
FROM->WHERE->GROUP BY->SELECT->HAVING->ORDER BY->LIMIT
因此,在您的 FULL OUTER JOIN
的情况下,当您指定 WHERE
子句时,它会根据连接的 table 的结果评估该子句(通常是临时 table 是为此创建的)。如果您希望行为是 A
中返回的唯一记录与 A.field = value
匹配,您需要先 select 来自 A
的那些记录,然后加入该结果到 B
table:
SELECT *
FROM (SELECT A.pk
FROM A
WHERE A.field = value) A
FULL OUTER JOIN B
ON A.pk = B.fk;
Here 是一个 SqlFiddle 所以你可以看到。
RECAP - 完全外部联接中使用的条件
我已经创建了最简单的场景,其中有 2 个表包含匹配记录和双方不匹配的记录,并测试了所有情况,在此 sqlfiddle 中:http://sqlfiddle.com/#!3/901cd2/11
fiddle 是基于@JRLambert 的回答,我已经接受了他的回答。本回答仅作总结和保管。
这里有SQL个关于这个fiddle的查询和解释(以防有一天它消失):
-- Basic full join
-- Returns (a,b) for matching records, and also (a, null) and (null, b)
-- for all records from A and B without matches
SELECT * FROM A
FULL OUTER JOIN B
ON A.pk = B.fk;
-- With condition in the ON clause
-- Only joins results (a,b) if conditions are satisfied on A.
-- The example returns :
-- 1. (a,b) only if A and B records are matched, and a.field = 0
-- 2. (a, null) for unmatched A records, and also all values of A with A.field != 0 (even if there is a matching B record)
-- 3. (null, b) for all unmatched B records, or with matching A records not satisfying the condition
SELECT * FROM A
FULL OUTER JOIN B
ON A.pk = B.fk AND A.field = 0;
-- With condition in the WHERE clause
-- Joins all matching record first, and return only pairs (a,b) and (a, null) if a satisfied the condition.
-- This example joins as the first "Basic full join", and then only returns rows with a satisfying the condition (meaning cannot be null)
SELECT * FROM A
FULL OUTER JOIN B
ON A.pk = B.fk
WHERE A.field = 0;
-- To select all join results satisfying the condition on A,
-- but keeping all B results as (null,b) whenever the condition is not true on A,
-- preselect keys before the join
SELECT *
FROM (SELECT A.pk FROM A WHERE A.field = 0) A
FULL OUTER JOIN B
ON A.pk = B.fk;