62

I have the below table with the below records in it

create table employee ( EmpId number, EmpName varchar2(10), EmpSSN varchar2(11) ); insert into employee values(1, 'Jack', '555-55-5555'); insert into employee values (2, 'Joe', '555-56-5555'); insert into employee values (3, 'Fred', '555-57-5555'); insert into employee values (4, 'Mike', '555-58-5555'); insert into employee values (5, 'Cathy', '555-59-5555'); insert into employee values (6, 'Lisa', '555-70-5555'); insert into employee values (1, 'Jack', '555-55-5555'); insert into employee values (4, 'Mike', '555-58-5555'); insert into employee values (5, 'Cathy', '555-59-5555'); insert into employee values (6 ,'Lisa', '555-70-5555'); insert into employee values (5, 'Cathy', '555-59-5555'); insert into employee values (6, 'Lisa', '555-70-5555'); 

I dont have any primary key in this table .But i have the above records in my table already. I want to remove the duplicate records which has the same value in EmpId and EmpSSN fields.

Ex : Emp id 5

How can I frame a query to delete those duplicate records?

4
  • Can you ADD a primary key?? What database system or you using? Oracle? Please specify so in your question! Commented Jun 12, 2009 at 7:19
  • 2
    What if it has the same EmpID and EmpSSn, but different names? Commented Jun 12, 2009 at 7:24
  • We don't have varchar2 in SQL Server, any version Commented Jun 12, 2009 at 10:14
  • Hmmm... neither "number" nor "varchar2" are valid SQL Server 2005 data types.... smells like Oracle to me. Commented Jun 12, 2009 at 10:52

20 Answers 20

88

It is very simple. I tried in SQL Server 2008

DELETE SUB FROM (SELECT ROW_NUMBER() OVER (PARTITION BY EmpId, EmpName, EmpSSN ORDER BY EmpId) cnt FROM Employee) SUB WHERE SUB.cnt > 1 
Sign up to request clarification or add additional context in comments.

2 Comments

This works well when you have a lot of columns to group by, and it neatly deals with the NULL != NULL when comparing two columns. You don't have to list each column twice like some of the other answers ("a.col = b.col" type thing), and even more importantly, you don't have to check "((a.col = b.col) OR (a.col IS NULL AND b.col IS NULL))" on NULL columns.
This answer actually resolves the problem, without structural changes. Works perfectly.
60

Add a Primary Key (code below)

Run the correct delete (code below)

Consider WHY you woudln't want to keep that primary key.


Assuming MSSQL or compatible:

ALTER TABLE Employee ADD EmployeeID int identity(1,1) PRIMARY KEY; WHILE EXISTS (SELECT COUNT(*) FROM Employee GROUP BY EmpID, EmpSSN HAVING COUNT(*) > 1) BEGIN DELETE FROM Employee WHERE EmployeeID IN ( SELECT MIN(EmployeeID) as [DeleteID] FROM Employee GROUP BY EmpID, EmpSSN HAVING COUNT(*) > 1 ) END 

7 Comments

+1: to quote some SQL god: "if it doesn't have a primary key, it's not a table"
+1 A primary key identifies a row. No PK = no sense. @marc_s: a clustered index differentiates a table from a heap. No PK simply means no data integrity
@gbn: even a heap is considered a table :-) This quote was more along the lines: unless you specify a primary key, a table really doesn't have much usefulness (except in edge cases like bulk import / temporary tables etc.)
even in those edge cases I almost always add a primary key, just so I can delete dupped recrds if need be.
Looks like the duplicate removal is being done so the EmpID can be the primary key. The other data seems dependant on it.
|
25

Use the row number to differentiate between duplicate records. Keep the first row number for an EmpID/EmpSSN and delete the rest:

 DELETE FROM Employee a WHERE ROW_NUMBER() <> ( SELECT MIN( ROW_NUMBER() ) FROM Employee b WHERE a.EmpID = b.EmpID AND a.EmpSSN = b.EmpSSN ) 

2 Comments

+1 A good solution to avoid having to make structural changes
Will it work for Oracle? I had this issue stackoverflow.com/questions/34948301/…
13
With duplicates As (Select *, ROW_NUMBER() Over (PARTITION by EmpID,EmpSSN Order by EmpID,EmpSSN) as Duplicate From Employee) delete From duplicates Where Duplicate > 1 ; 

This will update Table and remove all duplicates from the Table!

Comments

8
select distinct * into newtablename from oldtablename 

Now, the newtablename will have no duplicate records.

Simply change the table name(newtablename) by pressing F2 in object explorer in sql server.

Comments

8

Code

DELETE DUP FROM ( SELECT ROW_NUMBER() OVER (PARTITION BY Clientid ORDER BY Clientid ) AS Val FROM ClientMaster ) DUP WHERE DUP.Val > 1 

Explanation

Use an inner query to construct a view over the table which includes a field based on Row_Number(), partitioned by those columns you wish to be unique.

Delete from the results of this inner query, selecting anything which does not have a row number of 1; i.e. the duplicates; not the original.

The order by clause of the row_number window function is needed for a valid syntax; you can put any column name here. If you wish to change which of the results is treated as a duplicate (e.g. keep the earliest or most recent, etc), then the column(s) used here do matter; i.e. you want to specify the order such that the record you wish to keep will come first in the result.

2 Comments

Welcome to Stack Overflow! Code only answers are not very useful on their own. It would help if you could add some detail explaining how/why it answers the question.
I was surprised to learn you can delete rows from an alias (or a view), and when you do this, the corresponding row(s) will be deleted from the underlying table! I read more about "updatable views" here - "You can modify the data of an underlying base table through a view, as long as the following conditions are true..."
7

You could create a temporary table #tempemployee containing a select distinct of your employee table. Then delete from employee. Then insert into employee select from #tempemployee.

Like Josh said - even if you know the duplicates, deleting them will be impossile since you cannot actually refer to a specific record if it is an exact duplicate of another record.

3 Comments

Only trick there is if the names are different but the ID/SSN match. You'd have to somehow pick one because distinct wouldn't help there.
+1 this is the most straightforward and portable solution. OP does not state what brand of database he uses.
@Josh: from the OP's sample, it looks like that's not an issue. The duplicate rows are identical in all columns.
2

If you don't want to create a new primary key you can use the TOP command in SQL Server:

declare @ID int while EXISTS(select count(*) from Employee group by EmpId having count(*)> 1) begin select top 1 @ID = EmpId from Employee group by EmpId having count(*) > 1 DELETE TOP(1) FROM Employee WHERE EmpId = @ID end 

Comments

2

ITS easy use below query

WITH Dups AS ( SELECT col1,col2,col3, ROW_NUMBER() OVER(PARTITION BY col1,col2,col3 ORDER BY (SELECT 0)) AS rn FROM mytable ) DELETE FROM Dups WHERE rn > 1 

Comments

1

delete sub from (select ROW_NUMBER() OVer(Partition by empid order by empid)cnt from employee)sub where sub.cnt>1

1 Comment

Welcome to stackoverflow. This is an old question with a well established answer. IF you believe your answer adds something significant and new, please expand it with more explanation.
0

I'm not an SQL expert so bear with me. I'm sure you'll get a better answer soon enough. Here's how you can find the duplicate records.

select t1.empid, t1.empssn, count(*) from employee as t1 inner join employee as t2 on (t1.empid=t2.empid and t1.empssn = t2.empssn) group by t1.empid, t1.empssn having count(*) > 1 

Deleting them will be more tricky because there is nothing in the data that you could use in a delete statement to differentiate the duplicates. I suspect the answer will involve row_number() or adding an identity column.

Comments

0
create unique clustered index Employee_idx on Employee ( EmpId,EmpSSN ) with ignore_dup_key

You can drop the index if you don't need it.

Comments

0

no ID, no rowcount() or no temp table needed....

WHILE ( SELECT COUNT(*) FROM TBLEMP WHERE EMPNO IN (SELECT empno from tblemp group by empno having count(empno)>1)) > 1 DELETE top(1) FROM TBLEMP WHERE EMPNO IN (SELECT empno from tblemp group by empno having count(empno)>1) 

Comments

0

there are two columns in the a table ID and name where names are repeating with different IDs so for that you may use this query: . .

DELETE FROM dbo.tbl1 WHERE id NOT IN ( Select MIN(Id) AS namecount FROM tbl1 GROUP BY Name ) 

Comments

0

Having a database table without Primary Key is really and will say extremely BAD PRACTICE...so after you add one (ALTER TABLE)

Run this until you don't see any more duplicated records (that is the purpose of HAVING COUNT)

DELETE FROM [TABLE_NAME] WHERE [Id] IN ( SELECT MAX([Id]) FROM [TABLE_NAME] GROUP BY [TARGET_COLUMN] HAVING COUNT(*) > 1 ) SELECT MAX([Id]),[TABLE_NAME], COUNT(*) AS dupeCount FROM [TABLE_NAME] GROUP BY [TABLE_NAME] HAVING COUNT(*) > 1 

MAX([Id]) will cause to delete latest records (ones added after first created) in case you want the opposite meaning that in case of requiring deleting first records and leave the last record inserted please use MIN([Id])

Comments

0

Let's think out of the box.

I don't delete from the table, I make a new table first, for safety. I personally prefer do a

INSERT INTO new_table SELECT DISTINCT * FROM orig_table; 

Now, new_table now should contains the expected data I want. I can check new_table to ensure that.

Then I have 2 options to replace the orig_table

A. delete orig_table; rename new_table to orig_table

B. truncate orig_table; insert data from new_table to orig_table; delete new_table (Recommended: in case you have some trigger/something else linked to the original orig_table)

1 Comment

Good idea, but kind of a duplicate of stackoverflow.com/a/11119012/1260022
-1
select t1.* from employee t1, employee t2 where t1.empid=t2.empid and t1.empname = t2.empname and t1.salary = t2.salary group by t1.empid, t1.empname,t1.salary having count(*) > 1 

1 Comment

Which question does it answer?
-1

delete from employee where rowid in (select rowid from (select rowid, name_count from (select rowid, count(emp_name) as name_count from employee group by emp_id, emp_name) where name_count>1))

Comments

-2
DELETE FROM 'test' USING 'test' , 'test' as vtable WHERE test.id>vtable.id and test.common_column=vtable.common_column 

Using this we can remove duplicate records

Comments

-3
ALTER IGNORE TABLE test ADD UNIQUE INDEX 'test' ('b'); 

@ here 'b' is column name to uniqueness, @ here 'test' is index name.

1 Comment

Not remotely valid SQL Server syntax.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.