DELETE
テーブルの指定されたsidに対してMySQL
行を複製する必要があります。
SQLクエリでこれを行うにはどうすればよいですか?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
このようなものですが、私はそれを行う方法がわかりません。
これにより、新しいテーブルを作成せずに重複を削除します
ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)
注:インデックスがメモリに収まる場合にのみ機能します
次の列を持つテーブルemployee
があるとします。
employee (first_name, last_name, start_date)
first_name
列が重複している行を削除するには:
delete
from employee using employee,
employee e1
where employee.id > e1.id
and employee.first_name = e1.first_name
次に、単一のSIDだけでなく、すべてのSIDの重複を削除します。
一時テーブル付き
CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;
DROP TABLE table;
RENAME TABLE table_temp TO table;
temp_table
は新たに作成されるため、インデックスはありません。重複を削除した後、それらを再作成する必要があります。 SHOW INDEXES IN table
を使用して、テーブルにあるインデックスを確認できます。
一時テーブルなし:
DELETE FROM `table` WHERE id IN (
SELECT all_duplicates.id FROM (
SELECT id FROM `table` WHERE (`title`, `SID`) IN (
SELECT `title`, `SID` FROM `table` GROUP BY `title`, `SID` having count(*) > 1
)
) AS all_duplicates
LEFT JOIN (
SELECT id FROM `table` GROUP BY `title`, `SID` having count(*) > 1
) AS grouped_duplicates
ON all_duplicates.id = grouped_duplicates.id
WHERE grouped_duplicates.id IS NULL
)
テーブルを作成し、いくつかの行を挿入します:
dev-db> create table penguins(foo int, bar varchar(15), baz datetime);
Query OK, 0 rows affected (0.07 sec)
dev-db> insert into penguins values(1, 'skipper', now());
dev-db> insert into penguins values(1, 'skipper', now());
dev-db> insert into penguins values(3, 'kowalski', now());
dev-db> insert into penguins values(3, 'kowalski', now());
dev-db> insert into penguins values(3, 'kowalski', now());
dev-db> insert into penguins values(4, 'rico', now());
Query OK, 6 rows affected (0.07 sec)
dev-db> select * from penguins;
+------+----------+---------------------+
| foo | bar | baz |
+------+----------+---------------------+
| 1 | skipper | 2014-08-25 14:21:54 |
| 1 | skipper | 2014-08-25 14:21:59 |
| 3 | kowalski | 2014-08-25 14:22:09 |
| 3 | kowalski | 2014-08-25 14:22:13 |
| 3 | kowalski | 2014-08-25 14:22:15 |
| 4 | rico | 2014-08-25 14:22:22 |
+------+----------+---------------------+
6 rows in set (0.00 sec)
その後、重複を削除します:
dev-db> delete a
-> from penguins a
-> left join(
-> select max(baz) maxtimestamp, foo, bar
-> from penguins
-> group by foo, bar) b
-> on a.baz = maxtimestamp and
-> a.foo = b.foo and
-> a.bar = b.bar
-> where b.maxtimestamp IS NULL;
Query OK, 3 rows affected (0.01 sec)
結果:
dev-db> select * from penguins;
+------+----------+---------------------+
| foo | bar | baz |
+------+----------+---------------------+
| 1 | skipper | 2014-08-25 14:21:59 |
| 3 | kowalski | 2014-08-25 14:22:15 |
| 4 | rico | 2014-08-25 14:22:22 |
+------+----------+---------------------+
3 rows in set (0.00 sec)
削除ステートメントの実行内容
擬似コード:重複を削除する2つの列で行をグループ化します。最大集計を使用して、保持する各グループの1行を選択します。左結合は、左のテーブルからすべての行を返し、一致する行を右のテーブルに返します。この場合、左側のテーブルにはテーブル内のすべての行があり、右側には保持する行ごとではなく、NULLの行のみが含まれます。これらの行を削除すると、グループごとに一意の行のみが残ります。
詳細な技術的説明、そのsql deleteステートメントの読み方:
エイリアス「a」を持つテーブルペンギンは、エイリアス「b」と呼ばれるテーブルペンギンのサブセットに結合されたままになります。サブセットである右側のテーブル「b」は、fooとbarでグループ化された最大タイムスタンプを見つけます。これは、左側のテーブル「a」に一致します。左側の(foo、bar、baz)には、テーブル内のすべての行があります。右側のサブセット 'b'には(maxtimestamp、foo、bar)があり、これはIS maxの左側にのみ一致します。
その最大ではないすべての行の値はNULLのmaxtimestampです。それらのNULL行をフィルターダウンすると、fooとbarでグループ化されたすべての行のセットがあり、それは最新のタイムスタンプbazではありません。それらを削除します。
これを実行する前に、テーブルのバックアップを作成します。
この問題がこのテーブルで再び発生するのを防ぎます:
これが機能するようになり、「重複行」が発生した場合。すばらしいです。あなたの仕事はまだ終わっていません。テーブルに(これらの2つの列に)新しい複合一意キーを定義して、そもそも重複が追加されないようにします。優れた免疫システムのように、挿入時に不良な行をテーブルに入れてはいけません。後で重複を追加するこれらすべてのプログラムは抗議をブロードキャストします。それらを修正すると、この問題は二度と起こりません。
自分でこの問題に遭遇した後、巨大なデータベースで、私は他の答えのパフォーマンスに完全に感銘を受けませんでした。最新の重複行のみを保持し、残りを削除したい。
一時テーブルを使用しない1クエリステートメントでは、これが最適でした。
DELETE e.*
FROM employee e
WHERE id IN
(SELECT id
FROM (SELECT MIN(id) as id
FROM employee e2
GROUP BY first_name, last_name
HAVING COUNT(*) > 1) x);
唯一の注意点は、クエリを複数回実行する必要があることですが、それでも、他のオプションよりもうまく機能することがわかりました。
これは常に私のために働くようです:
CREATE TABLE NoDupeTable LIKE DupeTable;
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;
それぞれの重複と残りの重複しないレコードで最も低いIDを保持します。
また、削除後に重複の問題が発生しないように、次のことも行いました。
CREATE TABLE NoDupeTable LIKE DupeTable;
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;
つまり、最初のテーブルの複製を作成し、複製したくないフィールドに一意のインデックスを追加してから、Insert IGNORE
を実行します。これは、最初の試行時に通常のInsert
として失敗しないという利点があります2つのフィールドに基づいて重複レコードを追加し、そのようなレコードは無視します。
Fwdを移動すると、これらの2つのフィールドに基づいて重複するレコードを作成できなくなります。
簡単な答えを次に示します。
delete a from target_table a left JOIN (select max(id_field) as id, field_being_repeated
from target_table GROUP BY field_being_repeated) b
on a.field_being_repeated = b.field_being_repeated
and a.id_field = b.id_field
where b.id_field is null;
以下はすべてのテーブルで機能します
CREATE TABLE `noDup` LIKE `Dup` ;
INSERT `noDup` SELECT DISTINCT * FROM `Dup` ;
DROP TABLE `Dup` ;
ALTER TABLE `noDup` RENAME `Dup` ;
これは私にとって古いレコードを削除するのに役立ちます:
delete from table where id in
(select min(e.id)
from (select * from table) e
group by column1, column2
having count(*) > 1
);
Min(e.id)をmax(e.id)に置き換えて、最新のレコードを削除できます。
この手順は、テーブル内のすべての重複(複数を含む)を削除し、最後の重複を保持します。これは 各グループの最後のレコードを取得する の拡張です
これが誰かに役立つことを願っています。
DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));
INSERT INTO UniqueIDs
(SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
(T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields
AND T1.ID < T2.ID)
WHERE T2.ID IS NULL);
DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);
delete p from
product p
inner join (
select max(id) as id, url from product
group by url
having count(*) > 1
) unik on unik.url = p.url and unik.id != p.id;
別の簡単な方法... UPDATE IGNOREを使用:
Uは、1つ以上の列のインデックス(タイプインデックス)を使用する必要があります。新しい一時参照列を作成します(インデックスの一部ではありません)。この列では、ignore句を使用して更新することで一意をマークします。ステップバイステップ:
一時的な参照列を追加して、一意をマークします。
ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;
=>これにより、テーブルに列が追加されます。
テーブルを更新し、すべてを一意としてマークしますが、重複キーの問題による可能性のあるエラーを無視します(レコードはスキップされます)。
UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;
=>重複レコードは一意としてマークされません= 'はい'、つまり、重複レコードの各セットのうち1つだけが一意としてマークされます。
一意ではないものをすべて削除します。
DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';
=>これにより、すべての重複レコードが削除されます。
列をドロップ...
ALTER TABLE `yourtable` DROP `unique`;
Wernerのソリューション 上記 が最も便利であると思います。主キーの存在に関係なく機能し、テーブルを混乱させず、将来性のあるプレーンなSQLを使用し、非常に理解しやすいからです。
私のコメントで述べたように、その解決策は適切に説明されていません。それに基づいて、これは私のものです。
1)新しいブール列を追加する
alter table mytable add tokeep boolean;
2)複製された列と新しい列に制約を追加します
alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);
3)ブール列をtrueに設定します。これは、新しい制約のため、複製された行の1つでのみ成功します。
update ignore mytable set tokeep = true;
4)tokeepとしてマークされていない行を削除する
delete from mytable where tokeep is null;
5)追加した列をドロップします
alter table mytable drop tokeep;
追加した制約を保持して、新しい重複が将来的に防止されるようにすることをお勧めします。
MySQLテーブルの重複を削除することは一般的な問題であり、通常は特定のニーズが伴います。誰かが興味がある場合は、ここ( MySQLで重複する行を削除する )さまざまなユースケース用)。
ALi 、あなたの場合、次のようなものを実行できます:
-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;
-- add a unique constraint
ALTER TABLE tmp_table1 ADD UNIQUE(sid, 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;
これは大きなテーブルで機能します:
CREATE Temporary table duplicates AS select max(id) as id, url from links group by url having count(*) > 1;
DELETE l from links l inner join duplicates ld on ld.id = l.id WHERE ld.id IS NOT NULL;
最も古い変更max(id)
をmin(id)
に削除するには
これは基本的にテーブルをコピーして空にし、個別の値のみを戻すことで機能すると思いますが、大量のデータで実行する前に再確認してください。
テーブルのカーボンコピーを作成します
oldtablenameのようなテーブルtemp_tableを作成します。挿入temp_table select * from oldtablename;
元のテーブルを空にします
DELETE * from oldtablename;
コピーされたテーブルからすべての個別の値を元のテーブルにコピーして戻します
Firsttable、lastname、dobによるtemp_tableグループからのoldtablename SELECT *の挿入
一時テーブルを削除します。
テーブルtemp_tableの削除
区別したいaLLフィールドでグループ化する必要があります。
DELETE T2
FROM table_name T1
JOIN same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
delete from `table` where `table`.`SID` in
(
select t.SID from table t join table t1 on t.title = t1.title where t.SID > t1.SID
)
@ericの答えが大好きですが、本当に大きなテーブルがある場合は動作しないようです(実行しようとするとThe SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay
が得られます)。したがって、重複する行のみを考慮するように結合クエリを制限し、次のようになりました。
DELETE a FROM penguins a
LEFT JOIN (SELECT COUNT(baz) AS num, MIN(baz) AS keepBaz, foo
FROM penguins
GROUP BY deviceId HAVING num > 1) b
ON a.baz != b.keepBaz
AND a.foo = b.foo
WHERE b.foo IS NOT NULL
この場合のWHERE句により、MySQLは重複のない行を無視し、これが重複の最初のインスタンスである場合も無視するため、後続の重複のみが無視されます。 MIN(baz)
をMAX(baz)
に変更して、最初ではなく最後のインスタンスを保持します。
これにより、列column_name
が主キーになり、それまではすべてのエラーが無視されます。したがって、column_name
の重複値を持つ行を削除します。
ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);