想象一下有四列的表:A,B,C和D. 如果我有多个行,其中4个值相同(但它们可能位于不同的列中),如何只保留其中一行并删除其他行? (哪一个留下来并不重要)
示例:
A B C D
----------
1 2 2 3
3 2 1 2
2 1 2 3
2 2 1 3
1 8 8 8
8 1 8 8
结果应该是:
A B C D
----------
1 2 2 3
8 1 8 8
这个问题是否可能没有使用:scalar子查询,union / union all
允许:加入,CTE,rank / dense_rank / row_number / count,案例表达式
答案 0 :(得分:2)
而不是@Plirkee提出的分层查询功能,您可以取消数据(子查询T1
),使用函数list_agg()
(子查询T2
)中的正确排序对它们进行排序,以便查找对于每个唯一列表具有最小rowid
的行,删除其余行:
delete from t where rowid not in (
with t1 as (select rd, col, val
from (select rowid rd, a, b, c, d from t)
unpivot (val for (col) in ("A", "B", "C", "D"))),
t2 as (select rd,
listagg(val, '-') within group (order by val)
over (partition by rd) as list
from t1)
select min(rd) from t2 group by list )
这适用于我的测试数据。如果列A,B,C,D是正数,则没有问题。如果它们是负面或字符串,可能会发生奇怪的事情,特别是包含' - '。在这种情况下,您应该使用listagg()
的其他分隔符。
答案 1 :(得分:1)
好吧,我将借助于对给定字符串中的字符进行排序的函数来完成此操作。 所以首先让我们创建一个函数
create or replace function sortString(str in Varchar2) return varchar2 is
res varchar2(500);
begin
SELECT MIN(permutations) into res
FROM (SELECT REPLACE (SYS_CONNECT_BY_PATH (n, ','), ',') permutations
FROM (SELECT LEVEL l, SUBSTR (str, LEVEL, 1) n
FROM DUAL
CONNECT BY LEVEL <= LENGTH (str)) yourtable
CONNECT BY NOCYCLE l != PRIOR l)
WHERE LENGTH (permutations) = LENGTH (str);
return res;
end;
之后
DELETE FROM
table_name A
WHERE
a.rowid >
ANY (
SELECT
B.rowid
FROM
table_name B
WHERE
sortString(A.col1 ||A.col2 || A.col3 ||A.col4)=sortString(B.col1 || B.col2 || B.col3 || B.col4)
);
一些参考文献:sortString(1),delete duplicates(2)