为什么 OUTER JOIN 需要相等规则?
Why does OUTER JOIN need an equality rule?
让我们想象 2 tables:
客户:
cust_id
1000000001
1000000002
1000000003
1000000004
1000000005
订单:
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
让我们想象 2 tables:
客户:
cust_id 1000000001 1000000002 1000000003 1000000004 1000000005 订单:
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