在上篇文章中,我们的测试用表,没一行都是唯一的,也就是没有重复值,如果有重复值,结论会不会变呢?
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 右连接。