有没有人有一个优雅的sql语句来删除表中的重复记录,但只有当x重复数超过x时?所以它允许最多2或3个副本,但就是这样吗?
目前我有一个select语句执行以下操作:
delete table
from table t
left outer join (
select max(id) as rowid, dupcol1, dupcol2
from table
group by dupcol1, dupcol2
) as keeprows on t.id=keeprows.rowid
where keeprows.rowid is null
这很有效。但现在我想做的只是删除那些行,如果他们有超过2个重复。
由于
答案 0 :(得分:7)
with cte as (
select row_number() over (partition by dupcol1, dupcol2 order by ID) as rn
from table)
delete from cte
where rn > 2; -- or >3 etc
查询为每条记录制作一个“行号”,按(dupcol1,dupcol2)分组并按ID排序。实际上,此行号计数具有相同dupcol1和dupcol2的“重复”,然后按ID排序,然后分配数字1,2,3 .. N.如果您只想保留2个'重复',那么您需要删除分配了数字3,4,.. N
的那些,这是由DELLETE.. WHERE rn > 2;
使用此方法,您可以更改ORDER BY
以符合您的首选订单(例如ORDER BY ID DESC
),以便LATEST
具有rn=1
,然后是最新的是rn = 2,依此类推。其余的保持不变,DELETE
将只删除最旧的那些,因为它们具有最高的行号。
与this closely related question不同,随着条件变得更加复杂,使用CTE和row_number()会变得更简单。如果不存在适当的访问索引,性能可能仍然存在问题。
答案 1 :(得分:3)
HAVING
是你的朋友
select id, count(*) cnt from table group by id having cnt>2
答案 2 :(得分:1)
您可以尝试以下查询:
DELETE FROM table t1
WHERE rowid IN
(SELECT MIN(rowid) FROM table t2 GROUP BY t2.id,t2.name HAVING COUNT(rowid)>3);
答案 3 :(得分:0)
很晚但最简单的解决方案可能如下 假设我们有表emp_dept(empid,deptid),它有重复的行, 在这里,我使用@Count作为varibale ..例如2重复允许然后@count = 2 在Oracle数据库
delete from emp_dept where @Count <= ( select count(1) from emp_dept i where i.empid = emp_dept.empid and i.deptid = emp_dept.deptid and i.rowid < emp_dept.rowid )
在sql server或不支持row id kinda功能的任何数据库上,我们需要添加标识列以识别每一行。 说我们已经将nid添加为表格
alter table emp_dept add nid int identity(1,1) -- to add identity column
现在查询删除副本可以写成
delete from emp_dept where @@Count <= ( select count(1) from emp_dept i where i.empid = emp_dept.empid and i.deptid = emp_dept.deptid and i.nid< emp_dept.nid )
这里的概念是删除存在其他行的所有行,这些行具有相似的核心值但是n或更大的较小的rowid或identity的数量。因此,如果存在重复行,则具有较高行ID或标识的行将被删除。并且对于行没有重复,它无法找到较低的行ID,因此不会被删除。