You may use the COUNT aggregated function for the removing of all of the duplicated rows.
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
The COUNT count the rows for each unique key defined in the PARTITION BY clause.
The final query selects only the unique rows, i.e. rows with 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
Note: using ROW_NUMBER instead of COUNT you can do deduplication, i.e. you let one of the duplicated rows in the result and remove the duplicates.
Note that this method requires a sort of the table (WINDOW SORT), which may be heavy for large tables. In this case a method using NOT EXISTS may yield better performance, as it is transformed and performed as anti hash join - 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
)
Some care must be taken if the deduplication column (principal) is nullable. Contrary to the first solution with COUNT the not exusts leaves all the nulls in the result. If this is not required you must add a filter:
and t.principal is not NULL
If you have an index on the pricipal column, the optimal execution plan looks as follows
--------------------------------------
| 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)