为什么 OUTER JOIN 需要相等规则?

Why does OUTER JOIN need an equality rule?

让我们想象 2 tables:

  1. 客户:

    cust_id
    1000000001
    1000000002
    1000000003
    1000000004
    1000000005
  2. 订单:

    cust_id order_num
    1000000001 20005
    1000000003 20006
    1000000005 20008
    1000000001 20009

下面的代码对我来说非常清楚。它根据 cust_id 列的相等性比较 2 tables 并加入那些 tables.

SELECT Customers.cust_id, Orders.order_num
FROM Customers
INNER JOIN Orders ON Customers.cust_id = Orders.cust_id;

结果显而易见:

cust_id order_num
1000000001 20005
1000000003 20006
1000000005 20008
1000000001 20009

但是,如果我使用具有相同规则的 OUTER JOIN 方法:

SELECT Customers.cust_id, Orders.order_num
FROM Customers
FULL OUTER JOIN Orders ON Customers.cust_id = Orders.cust_id;

我会得到:

cust_id order_num
1000000001 20005
1000000001 20009
1000000002 NULL
1000000003 20006
1000000004 NULL
1000000005 20008

这个结果对我来说很清楚,我知道 FULL OUTER JOIN 做了什么,但我发现这个方法需要相等规则的事实非常模糊,因为代码 returns 从第一行开始的一些行table 不在第二个 table 中。那么,如果它被忽略了,为什么我们需要这条规则呢?我们可以使用不同的条件吗? != 以避免混淆?

您将交叉连接与 inner/outer(left,right,full) 连接混淆了。交叉联接将无条件地将每一行与其他每一行匹配。 inner/outer 连接匹配那些满足 ON 子句中的条件。内部联接和外部联接之间的主要区别在于 non-match 的处理方式。 non-match 概念不适用于交叉连接。

尝试 运行 这些查询作为示例。请注意最后几个使用完全外部联接的查询。 1=1 的 ON 子句模拟交叉连接。带有 1=0 returns 的 ON 子句每个 table.

一条记录

顺便说一句,我在 1=1 的 ON 子句中添加了一个 ORDER BY,因为该顺序不是交叉连接的顺序。 (希望它易于比较。)即使没有 ORDER BY 子句,对于这个非常小的例子,使用交叉连接的这个技巧的成本大约是 100 倍。

set nocount on

print 'Inner join:'

select * 
from (
    values (1,'A'),(2,'B'),(3,'C'),(25,'Y')
) t1 (id, val)
inner join (
    values (1, 'A'),(2,'B'),(3,'C'),(26,'Z')
) t2 (id, val)
ON t1.id = t2.id

print 'Left outer join:'

select * 
from (
    values (1,'A'),(2,'B'),(3,'C'),(25,'Y')
) t1 (id, val)
left outer join (
    values (1, 'A'),(2,'B'),(3,'C'),(26,'Z')
) t2 (id, val)
ON t1.id = t2.id

print 'Right outer join:'

select * 
from (
    values (1,'A'),(2,'B'),(3,'C'),(25,'Y')
) t1 (id, val)
right outer join (
    values (1, 'A'),(2,'B'),(3,'C'),(26,'Z')
) t2 (id, val)
ON t1.id = t2.id

print 'Full outer join:'

select * 
from (
    values (1,'A'),(2,'B'),(3,'C'),(25,'Y')
) t1 (id, val)
full outer join (
    values (1, 'A'),(2,'B'),(3,'C'),(26,'Z')
) t2 (id, val)
ON t1.id = t2.id

print 'Cross join:'

select * 
from (
    values (1,'A'),(2,'B'),(3,'C'),(25,'Y')
) t1 (id, val)
cross join (
    values (1, 'A'),(2,'B'),(3,'C'),(26,'Z')
) t2 (id, val)

print 'Full outer join with everything matching anything - a fake cross join:'

select * 
from (
    values (1,'A'),(2,'B'),(3,'C'),(25,'Y')
) t1 (id, val)
full outer join (
    values (1, 'A'),(2,'B'),(3,'C'),(26,'Z')
) t2 (id, val)
ON 1 = 1
ORDER BY t1.id, t2.id

print 'Full outer join with no matches ever:'

select * 
from (
    values (1,'A'),(2,'B'),(3,'C'),(25,'Y')
) t1 (id, val)
full outer join (
    values (1, 'A'),(2,'B'),(3,'C'),(26,'Z')
) t2 (id, val)
ON 1 = 0
Inner join:

id          val  id          val
----------- ---- ----------- ----
1           A    1           A
2           B    2           B
3           C    3           C

Left outer join:

id          val  id          val
----------- ---- ----------- ----
1           A    1           A
2           B    2           B
3           C    3           C
25          Y    NULL        NULL

Right outer join:

id          val  id          val
----------- ---- ----------- ----
1           A    1           A
2           B    2           B
3           C    3           C
NULL        NULL 26          Z

Full outer join:

id          val  id          val
----------- ---- ----------- ----
1           A    1           A
2           B    2           B
3           C    3           C
NULL        NULL 26          Z
25          Y    NULL        NULL

Cross join:

id          val  id          val
----------- ---- ----------- ----
1           A    1           A
1           A    2           B
1           A    3           C
1           A    26          Z
2           B    1           A
2           B    2           B
2           B    3           C
2           B    26          Z
3           C    1           A
3           C    2           B
3           C    3           C
3           C    26          Z
25          Y    1           A
25          Y    2           B
25          Y    3           C
25          Y    26          Z

Full outer join with everything matching anything - a fake cross join:

id          val  id          val
----------- ---- ----------- ----
1           A    1           A
1           A    2           B
1           A    3           C
1           A    26          Z
2           B    1           A
2           B    2           B
2           B    3           C
2           B    26          Z
3           C    1           A
3           C    2           B
3           C    3           C
3           C    26          Z
25          Y    1           A
25          Y    2           B
25          Y    3           C
25          Y    26          Z

Full outer join with no matches ever:

id          val  id          val
----------- ---- ----------- ----
1           A    NULL        NULL
2           B    NULL        NULL
3           C    NULL        NULL
25          Y    NULL        NULL
NULL        NULL 1           A
NULL        NULL 2           B
NULL        NULL 3           C
NULL        NULL 26          Z