在SQL中,执行OUTER JOIN时WHERE条件是否限制了结果数量?

时间:2015-12-04 03:47:48

标签: sql outer-join

如果我有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. 没有匹配的B行数A:(null,b)
  4. 但是,如果我在A上添加条件,例如:

    SELECT * FROM A FULL OUTER JOIN B ON A.pk = B.fk WHERE A.field = value;
    

    与上一个查询相比,第一组结果会发生什么?

    对于某些行,不满足A上的条件。那些类型" 1"成为" 3"在形式(null,b)中,这些将完全从结果中丢弃吗?

2 个答案:

答案 0 :(得分:0)

编写查询时,将按顺序编写不同的操作部分:

SELECT->FROM->WHERE->GROUP BY->HAVING->ORDER BY->LIMIT

但是查询是按顺序进行物理评估的:

FROM->WHERE->GROUP BY->SELECT->HAVING->ORDER BY->LIMIT

因此,对于FULL OUTER JOIN,当您指定WHERE子句时,它正在评估关于连接表结果的子句(通常为此创建临时表)。如果您希望行为是A中返回的唯一匹配A.field = value的记录,则需要先从A选择这些记录,然后将该结果加入{{ 1}}表:

B

Here是一个SqlFiddle所以你可以看到。

答案 1 :(得分:0)

RECAP - 完全外部加入中使用的条件

我创建了最简单的场景,其中2个表包含匹配记录和双方不匹配,并测试了所有案例,在此sqlfiddle:http://sqlfiddle.com/#!3/901cd2/11

小提琴是基于@JRLambert的回答,我已经接受了答案。这个答案仅用于总结和保管。

以下是这个小提琴的SQL查询和解释(如果它有一天消失的话):

-- 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;