您可以使用COUNT 聚合函数来删除所有重复的行。
select PRINCIPAL, APELLIDO, NOMBRE,
count(*) over (partition by PRINCIPAL) dup_cnt
from tab
P A N DUP_CNT
- - - ----------
a b c 2
a l m 2
b c d 1
c d e 1
COUNT 计算PARTITION BY 子句中定义的每个唯一键的行数。
最后的查询只选择唯一的行,即带有DUP_CNT = 1的行
with dedup as (
select PRINCIPAL, APELLIDO, NOMBRE,
count(*) over (partition by PRINCIPAL) dup_cnt
from tab)
select PRINCIPAL, APELLIDO, NOMBRE
from dedup
where dup_cnt = 1
注意:使用ROW_NUMBER 而不是COUNT,您可以进行重复数据删除,即您可以在结果中保留重复的行之一并删除重复的行。
请注意,此方法需要对表 (WINDOW SORT) 进行排序,这对于大型表可能很繁重。在这种情况下,使用NOT EXISTS 的方法可能会产生更好的性能,因为它被转换并作为反散列连接执行 - HASH JOIN RIGHT ANTI。
select principal, apellido, nombre
from tab t
where not exists
(select null
from tab
where principal = t.principal and rowid <> t.rowid
)
如果重复数据删除列 (principal) 可以为空,则必须小心。与COUNT 的第一个解决方案相反,not exusts 将所有nulls 留在结果中。如果不需要,您必须添加过滤器:
and t.principal is not NULL
如果您在pricipal 列上有索引,则最佳执行计划如下所示
--------------------------------------
| Id | Operation | Name |
--------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | HASH JOIN RIGHT ANTI | |
| 2 | INDEX FAST FULL SCAN| IDX |
|* 3 | TABLE ACCESS FULL | TAB |
--------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("PRINCIPAL"="T"."PRINCIPAL")
filter(ROWID<>"T".ROWID)
3 - filter("T"."PRINCIPAL" IS NOT NULL)