示例场景:
假设我们有两个表,记录了不同来源的员工信息:
-
employees_ny(纽约员工):id name department 1 Alice Sales 2 Bob IT 3 Carol HR 4 David Sales (注意:David在NY表) 5 Bob IT (注意:Bob在NY表重复出现,可能是录入错误) -
employees_sf(旧金山员工):id name department 101 Emma Marketing 102 Frank IT 103 Alice Sales (注意:Alice在SF表) 104 David Engineering (注意:David在SF表,部门不同) 105 Grace HR
目标: 获取一个包含所有地点员工的合并列表。
示例 1: 使用 UNION ALL (保留所有行,包括重复)
SELECT id, name, department, 'NY' AS location FROM employees_ny
UNION ALL
SELECT id, name, department, 'SF' AS location FROM employees_sf;
结果 (UNION ALL):
| id | name | department | location | |
|---|---|---|---|---|
| 1 | Alice | Sales | NY | |
| 2 | Bob | IT | NY | |
| 3 | Carol | HR | NY | |
| 4 | David | Sales | NY | (David NY) |
| 5 | Bob | IT | NY | (Bob 重复行 - 保留) |
| 101 | Emma | Marketing | SF | |
| 102 | Frank | IT | SF | |
| 103 | Alice | Sales | SF | (Alice 重复行 - 保留,地点不同) |
| 104 | David | Engineering | SF | (David SF - 保留,部门不同) |
| 105 | Grace | HR | SF |
解释:
-
结果集是
employees_ny和employees_sf所有行的直接堆叠。 -
所有重复行都被保留:
-
Bob (id=2 和 id=5) 都在 NY,姓名和部门完全重复。
-
Alice (NY id=1 和 SF id=103) 姓名和部门重复,但来源地点不同(
location列区分)。 -
David (NY id=4 和 SF id=104) 姓名重复,但部门不同,地点也不同。
-
-
效率较高: 数据库引擎只需要简单地将两个查询结果按顺序拼接起来,不需要进行额外的排序和去重操作。
-
符合规则:两个
SELECT都有 4 列 (id,name,department,location),对应列数据类型兼容。
示例 2: 使用 UNION (自动去重)
SELECT id, name, department, 'NY' AS location FROM employees_ny
UNION -- 这里省略了 ALL,等同于 UNION DISTINCT
SELECT id, name, department, 'SF' AS location FROM employees_sf;
结果 (UNION):
| id | name | department | location | |
|---|---|---|---|---|
| 1 | Alice | Sales | NY | |
| 2 | Bob | IT | NY | (只保留一个Bob) |
| 3 | Carol | HR | NY | |
| 4 | David | Sales | NY | (David NY) |
| 5 | Bob | IT | NY | (这个Bob被去重掉了!) |
| 101 | Emma | Marketing | SF | |
| 102 | Frank | IT | SF | |
| 103 | Alice | Sales | SF | (Alice SF 保留,因为location不同) |
| 104 | David | Engineering | SF | (David SF 保留,因为department不同) |
| 105 | Grace | HR | SF |
解释:
-
数据库引擎首先将两个表的所有行堆叠在一起(得到一个包含 10 行的临时结果集)。
-
然后对这个整个临时结果集执行去重 (
DISTINCT) 操作。 -
去重规则: 只有当两行的
SELECT列表中所有对应列的值都完全相同时,才会被认为是重复行并被移除一行。-
Bob (NY id=2 和 id=5):
id(2 vs 5) 不同,name(Bob vs Bob) 相同,department(IT vs IT) 相同,location(NY vs NY) 相同。关键点:id列不同! 虽然名字、部门、地点一样,但id不同,所以不被视为重复行。(注意:这个例子中id不同意味着它们是不同记录,UNION不会仅根据name去重) -
Alice (NY id=1 和 SF id=103):
id(1 vs 103) 不同,name(Alice vs Alice) 相同,department(Sales vs Sales) 相同,location(NY vs SF) 不同。因为location值不同,所以这两行不是重复行,都被保留。 -
David (NY id=4 和 SF id=104):
id(4 vs 104) 不同,name(David vs David) 相同,department(Sales vs Engineering) 不同,location(NY vs SF) 不同。因为department和location都不同,所以这两行不是重复行,都被保留。 -
(如果存在两行所有列值都完全一样,
UNION会只保留其中一行)
-
-
效率较低: 为了进行去重,数据库引擎通常需要对整个合并后的临时结果集进行排序(
SORT)操作,以便将相同的行分组在一起,然后移除重复项。这个排序操作在数据量大时是非常消耗资源的。因此UNION通常比UNION ALL慢得多。 -
符合规则:列数和数据类型要求同
UNION ALL。
注意:
-
all是可以省略,但是如果省略掉之后将结果拼接起来执行去重操作,如果有all则不会去重。没有设置all的时候执行合并,先对合并的数据进行排序操作,然后再执行去重操作,所以union的效率要远远低于union all。
-
合并的结果集必须要具有'相同的列数'。
-
合并的结果集中对应的列的'数据类型必须要相同'。
-
在实际工作过程中要用union all代替 union(一般实际工作中的数据都是优化过的数据,很少有重复的,但是也需要检查和以防万一)。去重请用其他的,distinct,group by 都可以。
补充注意点:
-
列名: 最终结果集的列名通常取自第一个
SELECT语句。即使第二个SELECT的列名不同(只要数据类型兼容),结果集也会使用第一个查询的列名。 -
排序: 如果需要最终结果有序,必须在整个
UNION/UNION ALL语句的最后加一个ORDER BY子句。在单个SELECT语句内加ORDER BY通常无效或会被覆盖(除非配合LIMIT等)。
6484

被折叠的 条评论
为什么被折叠?



