Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Query - Delete duplicates if more than 3 dups?

Does anyone have an elegant sql statement to delete duplicate records from a table, but only if there are more than x number of duplicates? So it allows up to 2 or 3 duplicates, but that's it?

Currently I have a select statement that does the following:

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

This works great. But now what I'd like to do is only delete those rows if they have more than say 2 duplicates.

Thanks

like image 281
Scott Klarenbach Avatar asked Jul 24 '09 00:07

Scott Klarenbach


3 Answers

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

The query is manufacturing a 'row number' for each record, grouped by the (dupcol1, dupcol2) and ordered by ID. In effect this row number counts 'duplicates' that have the same dupcol1 and dupcol2 and assigns then the number 1, 2, 3.. N, order by ID. If you want to keep just 2 'duplicates', then you need to delete those that were assigned the numbers 3,4,.. N and that is the part taken care of by the DELLETE.. WHERE rn > 2;

Using this method you can change the ORDER BY to suit your preferred order (eg.ORDER BY ID DESC), so that the LATEST has rn=1, then the next to latest is rn=2 and so on. The rest stays the same, the DELETE will remove only the oldest ones as they have the highest row numbers.

Unlike this closely related question, as the condition becomes more complex, using CTEs and row_number() becomes simpler. Performance may be problematic still if no proper access index exists.

like image 64
Remus Rusanu Avatar answered Sep 25 '22 12:09

Remus Rusanu


HAVING is your friend

select id, count(*) cnt from table group by id having cnt>2

like image 20
SquareCog Avatar answered Sep 22 '22 12:09

SquareCog


You can try the following query:

DELETE FROM table t1 
WHERE rowid IN
(SELECT MIN(rowid) FROM table t2 GROUP BY t2.id,t2.name HAVING COUNT(rowid)>3);
like image 42
Sree Gottumukkala Avatar answered Sep 24 '22 12:09

Sree Gottumukkala