在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 种结果的总和:

  1. 匹配的组合数(a,b)
  2. 没有匹配 B 的 A 行数:(a, null)
  3. 没有匹配 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;