web-dev-qa-db-ja.com

mysql dbから重複したエントリを削除するにはどうすればよいですか?

いくつかのIDとタイトルを含むテーブルがあります。タイトル列を一意にしたいのですが、すでに60万件を超えるレコードがあり、そのうちのいくつかは重複しています(場合によっては数十回以上)。

1つを除いてすべての重複を削除して、後でUNIQUEキーをタイトル列に追加するにはどうすればよいですか?

37
user15063

このコマンドは、一意のキーを追加し、(一意のキーが原因で)エラーを生成するすべての行を削除します。これにより、重複が削除されます。

ALTER IGNORE TABLE table ADD UNIQUE KEY idx1(title); 

編集:MySQLの一部のバージョンでは、このコマンド InnoDBテーブルでは機能しない可能性があります であることに注意してください。回避策については この投稿 を参照してください。 (この情報を提供してくれた「匿名ユーザー」に感謝します。)

79
unutbu

元のテーブルの個別の行だけで新しいテーブルを作成します。他の方法があるかもしれませんが、私はこれが最もきれいだと思います。

CREATE TABLE tmp_table AS SELECT DISTINCT [....] FROM main_table

より具体的に
より速い方法は、一時テーブルに個別の行を挿入することです。削除を使用すると、800万行のテーブルから重複を削除するのに数時間かかりました。インサートとディスティンクトを使用すると、わずか13分で完了しました。

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
DROP TABLE tableName;  
INSERT tableName SELECT * FROM tempTableName;  
DROP TABLE tempTableName;  
10
nc3b

以下のクエリを使用して、「id」フィールドの値が最も低い1つの行を除くすべての重複を削除できます。

DELETE t1 FROM table_name t1, table_name t2 WHERE t1.id > t2.id AND t1.name = t2.name

同様に、次のように「id」の値が最も高い行を保持できます。

 DELETE t1 FROM table_name t1, table_name t2 WHERE t1.id < t2.id AND t1.name = t2.name

MySQLテーブルの重複を削除することは一般的な問題であり、通常、特定のニーズが伴います。誰かが興味を持っている場合は、ここ( MySQLの重複行を削除 )一時テーブルを使用して、信頼性が高く高速な方法でMySQLの重複を削除する方法を説明します(さまざまな使用例の例を示します)。

この場合、次のようなものが機能します。

-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;

-- add a unique constraint    
ALTER TABLE tmp_table1 ADD UNIQUE(id, title);

-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;

-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;
0

MySql ALTER IGNORE TABLE廃止予定 、インデックスを追加する前に、重複する日付を実際に削除する必要があります。

最初に、すべての重複を見つけるクエリを記述します。ここでは、emailが重複を含むフィールドであると想定しています。

SELECT
    s1.email
    s1.id, 
    s1.created
    s2.id,
    s2.created 
FROM 
    student AS s1 
INNER JOIN 
    student AS s2 
WHERE 
    /* Emails are the same */
    s1.email = s2.email AND
    /* DON'T select both accounts,
       only select the one created later.
       The serial id could also be used here */
    s2.created > s1.created 
;

次に、一意の重複IDのみを選択します。

SELECT 
    DISTINCT s2.id
FROM 
    student AS s1 
INNER JOIN 
    student AS s2 
WHERE 
    s1.email = s2.email AND
    s2.created > s1.created 
;

削除する重複IDのみが含まれていることを確認したら、削除を実行します。追加する必要があります(SELECT * FROM tblname) MySqlが文句を言わないように。

DELETE FROM
    student 
WHERE
    id
IN (
    SELECT 
        DISTINCT s2.id
    FROM 
        (SELECT * FROM student) AS s1 
    INNER JOIN 
        (SELECT * FROM student) AS s2 
    WHERE 
        s1.email = s2.email AND
        s2.created > s1.created 
);

次に、一意のインデックスを作成します。

ALTER TABLE
    student
ADD UNIQUE INDEX
    idx_student_unique_email(email)
;
0

これは、SQL2000でそれを行う方法を示しています。私はMySQL構文に完全に精通していませんが、同等のものがあると確信しています

create table #titles (iid int identity (1, 1), title varchar(200))

-- Repeat this step many times to create duplicates
insert into #titles(title) values ('bob')
insert into #titles(title) values ('bob1')
insert into #titles(title) values ('bob2')
insert into #titles(title) values ('bob3')
insert into #titles(title) values ('bob4')


DELETE T  FROM 
#titles T left join 
(
  select title, min(iid) as minid from #titles group by title
) D on T.title = D.title and T.iid = D.minid
WHERE D.minid is null

Select * FROM #titles
0
souLTower
delete from student where id in (
SELECT distinct(s1.`student_id`) from student as s1 inner join student as s2
where s1.`sex` = s2.`sex` and
s1.`student_id` > s2.`student_id` and
s1.`sex` = 'M'
    ORDER BY `s1`.`student_id` ASC
)
0
Nitin

Nitinが投稿したソリューションは、最もエレガントで論理的なソリューションのようです。

ただし、1つの問題があります。

エラー1093(HY000):FROM句で更新するターゲットテーブル '学生'を指定できません

ただし、これは、studentの代わりに(SELECT * FROM student)を使用して解決できます。

DELETE FROM student WHERE id IN (
SELECT distinct(s1.`student_id`) FROM (SELECT * FROM student) AS s1 INNER JOIN (SELECT * FROM student) AS s2
WHERE s1.`sex` = s2.`sex` AND
s1.`student_id` > s2.`student_id` AND
s1.`sex` = 'M'
ORDER BY `s1`.`student_id` ASC
)

元の解決策を考え出すために、あなたの+1をNitinに渡してください。

0
StéphanS