Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I delete all the duplicate records in a MySQL table without temp tables

I've seen a number of variations on this but nothing quite matches what I'm trying to accomplish.

I have a table, TableA, which contain the answers given by users to configurable questionnaires. The columns are member_id, quiz_num, question_num, answer_num.

Somehow a few members got their answers submitted twice. So I need to remove the duplicated records, but make sure that one row is left behind.

There is no primary column so there could be two or three rows all with the exact same data.

Is there a query to remove all the duplicates?

like image 361
MivaScott Avatar asked Dec 26 '12 21:12

MivaScott


People also ask

Can you delete duplicate rows in a table without using a temporary table?

You can't. Fully duplicate records (ones which have every field equal) can't be deleted by one, because you can't differentiate them in a Where clause in a delete query. The only way would be to do a select distinct query to select all rows without duplicates, then insert them in an empty table.

How do you delete duplicate records from a table when the table does not have a primary key column?

So to delete the duplicate record with SQL Server we can use the SET ROWCOUNT command to limit the number of rows affected by a query. By setting it to 1 we can just delete one of these rows in the table. Note: the select commands are just used to show the data prior and after the delete occurs.


Video Answer


9 Answers

Add Unique Index on your table:

ALTER IGNORE TABLE `TableA`   
ADD UNIQUE INDEX (`member_id`, `quiz_num`, `question_num`, `answer_num`);

Another way to do this would be:

Add primary key in your table then you can easily remove duplicates from your table using the following query:

DELETE FROM member  
WHERE id IN (SELECT * 
             FROM (SELECT id FROM member 
                   GROUP BY member_id, quiz_num, question_num, answer_num HAVING (COUNT(*) > 1)
                  ) AS A
            );
like image 56
Saharsh Shah Avatar answered Oct 02 '22 01:10

Saharsh Shah


Instead of drop table TableA, you could delete all registers (delete from TableA;) and then populate original table with registers coming from TableA_Verify (insert into TAbleA select * from TAbleA_Verify). In this way you won't lost all references to original table (indexes,... )

CREATE TABLE TableA_Verify AS SELECT DISTINCT * FROM TableA;

DELETE FROM TableA;

INSERT INTO TableA SELECT * FROM TAbleA_Verify;

DROP TABLE TableA_Verify;
like image 41
jveirasv Avatar answered Oct 02 '22 00:10

jveirasv


This doesn't use TEMP Tables, but real tables instead. If the problem is just about temp tables and not about table creation or dropping tables, this will work:

SELECT DISTINCT * INTO TableA_Verify FROM TableA;

DROP TABLE TableA;

RENAME TABLE TableA_Verify TO TableA;
like image 21
christoph Avatar answered Oct 02 '22 02:10

christoph


Thanks to jveirasv for the answer above.

If you need to remove duplicates of a specific sets of column, you can use this (if you have a timestamp in the table that vary for example)

CREATE TABLE TableA_Verify AS SELECT * FROM TableA WHERE 1 GROUP BY [COLUMN TO remove duplicates BY];

DELETE FROM TableA;

INSERT INTO TableA SELECT * FROM TAbleA_Verify;

DROP TABLE TableA_Verify;
like image 22
nikolais Avatar answered Oct 02 '22 01:10

nikolais


Add Unique Index on your table:

ALTER IGNORE TABLE TableA   
ADD UNIQUE INDEX (member_id, quiz_num, question_num, answer_num);

is work very well

like image 37
Dina Elwy Avatar answered Oct 02 '22 02:10

Dina Elwy


If you are not using any primary key, then execute following queries at one single stroke. By replacing values:

# table_name - Your Table Name
# column_name_of_duplicates - Name of column where duplicate entries are found

create table table_name_temp like table_name;
insert into table_name_temp select distinct(column_name_of_duplicates),value,type from table_name group by column_name_of_duplicates;
delete from table_name;
insert into table_name select * from table_name_temp;
drop table table_name_temp
  1. create temporary table and store distinct(non duplicate) values
  2. make empty original table
  3. insert values to original table from temp table
  4. delete temp table

It is always advisable to take backup of database before you play with it.

like image 30
Sandesh Mhatre Avatar answered Oct 02 '22 02:10

Sandesh Mhatre


As noted in the comments, the query in Saharsh Shah's answer must be run multiple times if items are duplicated more than once.

Here's a solution that doesn't delete any data, and keeps the data in the original table the entire time, allowing for duplicates to be deleted while keeping the table 'live':

alter table tableA add column duplicate tinyint(1) not null default '0';

update tableA set
duplicate=if(@member_id=member_id
             and @quiz_num=quiz_num
             and @question_num=question_num
             and @answer_num=answer_num,1,0),
member_id=(@member_id:=member_id),
quiz_num=(@quiz_num:=quiz_num),
question_num=(@question_num:=question_num),
answer_num=(@answer_num:=answer_num)
order by member_id, quiz_num, question_num, answer_num;

delete from tableA where duplicate=1;

alter table tableA drop column duplicate;

This basically checks to see if the current row is the same as the last row, and if it is, marks it as duplicate (the order statement ensures that duplicates will show up next to each other). Then you delete the duplicate records. I remove the duplicate column at the end to bring it back to its original state.

It looks like alter table ignore also might go away soon: http://dev.mysql.com/worklog/task/?id=7395

like image 32
juacala Avatar answered Oct 02 '22 01:10

juacala


An alternative way would be to create a new temporary table with same structure.

CREATE TABLE temp_table AS SELECT * FROM original_table LIMIT 0

Then create the primary key in the table.

ALTER TABLE temp_table ADD PRIMARY KEY (primary-key-field)

Finally copy all records from the original table while ignoring the duplicate records.

INSERT IGNORE INTO temp_table AS SELECT * FROM original_table

Now you can delete the original table and rename the new table.

DROP TABLE original_table
RENAME TABLE temp_table TO original_table
like image 25
user1838915 Avatar answered Oct 02 '22 01:10

user1838915


Tested in mysql 5.Dont know about other versions. If you want to keep the row with the lowest id value:

DELETE n1 FROM 'yourTableName' n1, 'yourTableName' n2 WHERE n1.id > n2.id AND n1.member_id = n2.member_id and n1.answer_num =n2.answer_num

If you want to keep the row with the highest id value:

DELETE n1 FROM 'yourTableName' n1, 'yourTableName' n2 WHERE n1.id < n2.id AND n1.member_id = n2.member_id and n1.answer_num =n2.answer_num
like image 40
TanvirChowdhury Avatar answered Oct 02 '22 02:10

TanvirChowdhury