SQL 删除重复项,你想找出 EMP
表里不同的职位种类,但又不希望看到重复项。结果集应该如下所示。
SQL 删除重复项 问题描述
你想找出 EMP
表里不同的职位种类,但又不希望看到重复项。结果集应该如下所示。
JOB
---------
ANALYST
CLERK
MANAGER
PRESIDENT
SALESMAN
SQL 删除重复项 解决方案
所有的关系数据库管理系统都支持 DISTINCT
关键字,并且它也是从结果集中删除重复项的最简单的方法。然而,本实例将展示另外两种删除重复项的做法。
DB2、Oracle 和 SQL Server
传统的做法是使用 DISTINCT
,有时候也会用 GROUP BY
(正如后面的 MySQL 和 PostgreSQL 解决方案),这些方法适用于所有的关系数据库管理系统。下面给出的替代解决方案则使用了窗口函数 ROW_NUMBER OVER
。
1 select job
2 from (
3 select job,
4 row_number()over(partition by job order by job) rn
5 from emp
6 )x
7 where rn = 1
MySQL 和 PostgreSQL
使用 DISTINCT
关键字从结果集里删除重复项。
select distinct job
from emp
另外,也可以通过 GROUP BY
达到同样目的。
select job
from emp
group by job
SQL 删除重复项 扩展知识
DB2、Oracle 和 SQL Server
本解决方案展示了一种分区窗口函数(partitioned window function)的特殊用法。通过在 OVER
子句里使用 PARTITION BY
,当一种新的职位出现时,ROW_NUMBER
的返回值会被重置为 1。内嵌视图 X 的结果集如下所示。
select job,
row_number()over(partition by job order by job) rn
from emp
JOB RN
--------- ----------
ANALYST 1
ANALYST 2
CLERK 1
CLERK 2
CLERK 3
CLERK 4
MANAGER 1
MANAGER 2
MANAGER 3
PRESIDENT 1
SALESMAN 1
SALESMAN 2
SALESMAN 3
SALESMAN 4
每一行都被分配了一个递增的序号,当职位种类发生改变时,序号也会被重置为 1。为了删除重复项,我们需要筛选出 RN
等于 1 的那些行。
使用 ROW_NUMBER OVER
时,必须有一个 ORDER BY
子句(DB2 除外),但这并不影响最终结果。我们只是希望提取出每一种职位,至于每一个职位来自哪一行其实无关紧要。
MySQL 和 PostgreSQL
第一种解决方案展示了如何使用关键字 DISTINCT
从结果集里删除重复项。需要注意的是,DISTINCT
会对整个 SELECT
列表做限制;增加一列或者几列会改变最终的结果集。考虑下面两个查询的差异。
select distinct job select distinct job, deptno
from emp from emp
JOB JOB DEPTNO
--------- --------- ----------
ANALYST ANALYST 20
CLERK CLERK 10
MANAGER CLERK 20
PRESIDENT CLERK 30
SALESMAN MANAGER 10
MANAGER 20
MANAGER 30
PRESIDENT 10
SALESMAN 30
向 SELECT
列表里增加 DEPTNO
列的话,返回的就变成了 EMP
表里不同的 JOB/DEPTNO
组合值。
第二种解决方案使用 GROUP BY
删除重复项,以这种方式使用 GROUP BY
并不罕见。注意,GROUP BY
和 DISTINCT
是两个非常不同的子句,它们是不可互换的。为了给出全部可行的解决方案,我特地把使用 GROUP BY
去掉重复项的做法也包含进了本实例,这样读者下次看到类似做法时就不会有什么疑问了。