使用左連接和右連接代替全連接 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 右連接。

 

 

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