使用左连接和右连接代替全连接 2 (2 张表,值不唯一)

    在上篇文章中,我们的测试用表,没一行都是唯一的,也就是没有重复值,如果有重复值,结论会不会变呢?

2. 2 张表,值不唯的情况。

2.1 创建测试用表。

DROP TABLE IF EXISTS table1;

DROP TABLE IF EXISTS table2;

CREATE TABLE table1
(
    column_1 NUMERIC
);

INSERT INTO table1
VALUES (123);
INSERT INTO table1
VALUES (123);
INSERT INTO table1
VALUES (12);
INSERT INTO table1
VALUES (12);
INSERT INTO table1
VALUES (111);
INSERT INTO table1
VALUES (111);

CREATE TABLE table2
(
    column_2 NUMERIC
);

INSERT INTO table2
VALUES (123);
INSERT INTO table2
VALUES (123);
INSERT INTO table2
VALUES (12);
INSERT INTO table2
VALUES (12);
INSERT INTO table2
VALUES (23);
INSERT INTO table2
VALUES (23);

2.2. 查看表里的内容

查询 2-2-1: 查询表 1 内容。

SELECT *
FROM table1 t1;

输出 2-2-1:

123
123
12
12
111
111

查询 2-2-2: 查询表 2 内容。

SELECT *
FROM table2 t2;

输出 2-2-2:

123
123
12
12
23
23

查询 2-2-3: 全连接

SELECT *
FROM table1 t1
         FULL OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
ORDER BY column_1, column_2;

输出 2-2-3:

12    12
12    12
12    12
12    12
111    
111    
123    123
123    123
123    123
123    123
    23
    23

查询 2-2-4: 使用 UNION 合并左连接和右连接

SELECT *
FROM table1 t1
         LEFT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
UNION
SELECT *
FROM table1 t1
         RIGHT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
ORDER BY column_1, column_2;

输出:2-2-4:

12    12
111    
123    123
    23

解释 2-2-4: 输出 2-2-4 只有 4 行,而输出 2-2-3 有 12 行。因为 UNION 默认会删除重复的行,UNION ALL 则不会删除重复行。下面试试 UNION ALL:

查询 2-2-5: 使用 UNION ALL 合并左连接和右连接。

SELECT *
FROM table1 t1
         LEFT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
UNION ALL
SELECT *
FROM table1 t1
         RIGHT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
ORDER BY column_1, column_2;

输出 2-2-5:

12    12
12    12
12    12
12    12
12    12
12    12
12    12
12    12
111    
111    
123    123
123    123
123    123
123    123
123    123
123    123
123    123
123    123
    23
    23

解释 2-2-5: 输出 2-2-5 有 20 行,我们目标是想要获得 2-2-3, 只有 12 行。怎样才能使用左连接和右连接来获取这 10 行呢?目前来看,使用 UNION 或者 UNION ALL 拼接左连接和右连接都不行。

先来总结一下每种查询的行数,看看能不能有什么规律:

a. table1: 6 行。

b. table2: 6 行。

c. 内连接:8 行。

d. 左连接:10 行。

e. 右连接:10 行。

f. 全连接:12 行。

g. UNION 左连接和右连接:4 行。

h. UNION ALL 左连接和有连接:20 行。

猜想:h(20 行) - c(8 行) = f(12 行)。

下面进行验证。找了一下,UNION ALL 相当于查询结果相加,EXCETP 相当于相减。下面试一下 EXCETP:

查询 2-2-6: 使用 EXCETP 来删除一些行:

SELECT *
FROM table1 t1
         LEFT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
UNION ALL
SELECT *
FROM table1 t1
         RIGHT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
EXCEPT
SELECT *
FROM table1 t1
         INNER JOIN table2 t2 ON t1.column_1 = t2.column_2
ORDER BY column_1, column_2;

输出 2-2-6:

111    
    23

解释 2-2-6: 只有两行,没有获得我们想要的 12 行。分析原因:h(20 行) - c(8 行) = f(12 行) 这边的 h、c、f 都有重复的行,我们在使用 EXCETP 删除一些行的时候,比如 h 中有 line 1, line 2, 这两行是一样的,c 中有一行 line 3, 我们想要的结果是只删除 line 1, 但是 EXCETP 分不清 line 1 和 line 2,所以把 line 1 和 line 2 全删了。应该想办法 删除 line 1 保留 line 2.

查询 2-2-7: 使用 EXCETP 来删除左连接中的行,然后在与右连接 UNION ALL:

SELECT *
FROM table1 t1
         LEFT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
    EXCEPT
SELECT *
FROM table1 t1
         INNER JOIN table2 t2 ON t1.column_1 = t2.column_2
UNION ALL
SELECT *
FROM table1 t1
         RIGHT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
ORDER BY column_1, column_2;

输出 2-2-7:

12    12
12    12
12    12
12    12
111    
123    123
123    123
123    123
123    123
    23
    23

解释 2-2-7: 只有 11 行,并没有我们想要的 12 行。对比输出 2-2-3 和 2-2-7,我们发现少了这一行:

111    

下面来分析这一行是怎么少了的。

查询 2-2-8: 左连接 EXCEPT 内连接。

SELECT *
FROM table1 t1
         LEFT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
    EXCEPT
SELECT *
FROM table1 t1
         INNER JOIN table2 t2 ON t1.column_1 = t2.column_2;

输出 2-2-8:

111    

解释:左连接 10 行,内连接 8 行,左连接 EXCEPT 内连接只有 1 行。我们想要的是 2 行,不过这两行内容是一样的。难道 EXCEPT 有自动去重功能?

查询 2-2-9: 测试 EXCEPT 是否自带去重复功能。

SELECT *
FROM table1 t1
         LEFT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
    EXCEPT
SELECT *
FROM table1 t1
         INNER JOIN table2 t2 ON t1.column_1 = -1;

输出:

123    123
12    12
111    

解释 2-2-9: 果然,EXCPET 是有自动去重复功能的。左连接有 10 行,只有 3 行是互不相同的,使用了 EXCPET 之后,只显示了这 3 行。这里 EXCPET 后面的子查询的结果是空集,因为 table1 中没有 column_1 = -1 的行。UNION 后面加上 ALL 之后,去重功能就没有了,那么 EXCEPT 是不是也是这样呢?下面试一下:

查询 2-2-10: 左连接 EXCEPT ALL 内连接。

SELECT *
FROM table1 t1
         LEFT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
    EXCEPT ALL
SELECT *
FROM table1 t1
         INNER JOIN table2 t2 ON t1.column_1 = t2.column_2
ORDER BY column_1, column_2;

输出 2-2-10:

111    
111    

解释 2-2-10: 结果有 10 行,正是我们想要的 2 行。下面试一下左连接 EXCEPT ALL 内连接 UNION ALL 右连接。

查询 2-2-11: 左连接 EXCEPT ALL 内连接 UNION ALL 右连接。

SELECT *
FROM table1 t1
         LEFT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
EXCEPT ALL
SELECT *
FROM table1 t1
         INNER JOIN table2 t2 ON t1.column_1 = t2.column_2
UNION ALL
SELECT *
FROM table1 t1
         RIGHT OUTER JOIN table2 t2 ON t1.column_1 = t2.column_2
ORDER BY column_1, column_2;

输出 2-2-11:

12    12
12    12
12    12
12    12
111    
111    
123    123
123    123
123    123
123    123
    23
    23

解释 2-2-11: 结果有 12 行,与全连接的结果一样,正是我们想要的。

 

总结:

在 2 张表的情况下,全连接等效于:左连接 EXCEPT ALL 内连接 UNION ALL 右连接。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章