テーブルのDELETE
指定されたsidの行を複製する必要がありMySQL
ます。
SQLクエリでこれを行うにはどうすればよいですか?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
このような何かが、私はそれを行う方法がわかりません。
テーブルのDELETE
指定されたsidの行を複製する必要がありMySQL
ます。
SQLクエリでこれを行うにはどうすればよいですか?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
このような何かが、私はそれを行う方法がわかりません。
回答:
これは、新しいテーブルを作成せずに、重複を削除します
ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)
注:インデックスがメモリに収まる場合にのみ機能します
ALTER IGNORE
。
ALTER TABLE foo ENGINE MyISAM
それを回避するために走り、エンジンを元に戻しました。
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
employee
、1つのインデックスの一致のためにそれ自体に対して結合するよう>
であり、インデックスの1つのチェックが遅くなるようです。それがより良いのではないでしょうSELECT MAX(ID) FROM t GROUP BY unique
し、その後JOIN
の完全一致にID
しますかMAX(ID)
?
次に、単一のものだけでなく、すべての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
)
SELECT * FROM table GROUP BY title, SID;
それはすべて、自分が何をしているのかをどれだけよく知っているかにかかっています。
テーブルを作成し、いくつかの行を挿入します。
create table penguins(foo int, bar varchar(15), baz datetime);
insert into penguins values(1, 'skipper', now());
insert into penguins values(1, 'skipper', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(4, 'rico', now());
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)
重複箇所を削除します。
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)
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)
完了すると、重複する行が削除され、タイムスタンプによる最後の行が保持されます。
timestamp
ソートするための、または一意のインデックス列がありませんか?あなたは退化状態に住んでいます。重複する行を削除するには、追加の手順を実行する必要があります。
ペンギンテーブルを作成して行を追加する
create table penguins(foo int, bar varchar(15));
insert into penguins values(1, 'skipper');
insert into penguins values(1, 'skipper');
insert into penguins values(3, 'kowalski');
insert into penguins values(3, 'kowalski');
insert into penguins values(3, 'kowalski');
insert into penguins values(4, 'rico');
select * from penguins;
# +------+----------+
# | foo | bar |
# +------+----------+
# | 1 | skipper |
# | 1 | skipper |
# | 3 | kowalski |
# | 3 | kowalski |
# | 3 | kowalski |
# | 4 | rico |
# +------+----------+
最初のテーブルのクローンを作成し、それにコピーします。
drop table if exists penguins_copy;
create table penguins_copy as ( SELECT foo, bar FROM penguins );
#add an autoincrementing primary key:
ALTER TABLE penguins_copy ADD moo int AUTO_INCREMENT PRIMARY KEY first;
select * from penguins_copy;
# +-----+------+----------+
# | moo | foo | bar |
# +-----+------+----------+
# | 1 | 1 | skipper |
# | 2 | 1 | skipper |
# | 3 | 3 | kowalski |
# | 4 | 3 | kowalski |
# | 5 | 3 | kowalski |
# | 6 | 4 | rico |
# +-----+------+----------+
最大集計は、新しいmooインデックスに作用します。
delete a from penguins_copy a left join(
select max(moo) myindex, foo, bar
from penguins_copy
group by foo, bar) b
on a.moo = b.myindex and
a.foo = b.foo and
a.bar = b.bar
where b.myindex IS NULL;
#drop the extra column on the copied table
alter table penguins_copy drop moo;
select * from penguins_copy;
#drop the first table and put the copy table back:
drop table penguins;
create table penguins select * from penguins_copy;
観察とクリーンアップ
drop table penguins_copy;
select * from penguins;
+------+----------+
| foo | bar |
+------+----------+
| 1 | skipper |
| 3 | kowalski |
| 4 | rico |
+------+----------+
Elapsed: 1458.359 milliseconds
その大きなSQL削除ステートメントは何をしているのですか?
エイリアス「a」のテーブルペンギンは、エイリアス「b」と呼ばれるテーブルペンギンのサブセットに結合されたままになります。サブセットである右側のテーブル 'b'は、列fooとbarでグループ化された最大タイムスタンプ[またはmax moo]を見つけます。これは左側のテーブル「a」と一致します。(foo、bar、baz)の左側には、テーブルのすべての行があります。右側のサブセット 'b'には(maxtimestamp、foo、bar)があり、これは最大であるものにのみ左に一致します。
その最大ではないすべての行の値maxtimestampはNULLです。これらのNULL行をフィルターで絞り込むと、fooとbarでグループ化されたすべての行のセットがあり、これは最新のタイムスタンプbazではありません。それらを削除します。
これを実行する前に、テーブルのバックアップを作成してください。
この問題がこの表で二度と発生しないようにします。
これが機能し、「重複行」が発生した場合。すごい。次に、テーブル(これらの2つの列)に新しい複合一意キーを定義して、最初から重複が追加されないようにします。
優れた免疫システムのように、不良行は挿入時にテーブルに許可されるべきではありません。後で、重複を追加するすべてのプログラムで抗議がブロードキャストされ、修正すると、この問題が再発することはありません。
ID
列がある場合、ON
句はID
列と一致するだけで十分です。
この問題に自分で遭遇した後、巨大なデータベースで、他の回答のパフォーマンスに完全に感銘を受けたわけではありません。最新の重複行のみを保持し、残りを削除したい。
一時テーブルなしの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つのフィールドに基づく重複レコードを作成できなくなります。
ORDER BY
するSELECT
ためにが必要ではありませんNoDupeTable
か?
ORDER by ID Asc
傷つけることはできなかったので、それでも私は私の答えを編集します。
Select Max(ID)
、次にOrder by Max(ID)
けどどうなることすべては、挿入の順序を逆です。最高のIDを取得するには、上記の順序に関係なく、より複雑なselect結合が必要になると思います。これは、より低いIDからフィールド値を取得することになるためです。
MAX(ID)
かMIN(ID)
との代わりに、列名*
でSELECT FROM DupeTable
それ以外の場合はあなただけのものを得るでしょう、しかしID
「ランダムです。実際、多くのSQLやMySQL厳格なものでさえも、GROUP BY
節で指定されていない各列で集約関数を呼び出す必要があります。
ID,First,Last,Notes
と、レコード1,Bob,Smith,NULL
や2,Bob,Smith,Arrears
、その後やってSELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Last
両方の異なるIDを除いて、同じレコード、1を返します。Max(ID)が返され2,Bob,Smith,NULL
、Min(ID)が返され1,Bob,Smith,NULL
ます。ノートに「Arrears」を含む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;
and a.id_field = b.id
LEFT JOIN
するためにb
のみ比較する必要があるb.id
= a.id_field
と仮定するとfield_id
ユニークな自動インクリメントIDです。そうa.field_being_repeated = b.field_being_repeated
余分です。(また、b.id_field
それはだ、このクエリには存在しませんb.id
。
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;
上記の 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;
追加した制約を保持して、将来新しい重複が発生しないようにすることをお勧めします。
この手順は、テーブル内のすべての重複(複数を含む)を削除し、最後の重複を保持します。これは、各グループの最後のレコードの取得の拡張です。
これが誰かに役立つことを願っています。
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);
別の簡単な方法... UPDATE IGNOREを使用する:
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`;
unique
あります。列は、現在複製されている列と一緒に一意制約に追加する必要があります。そうしないと、SET unique
= 'Yes'が失敗しないため、全体が機能しません。
unique
mysqlキーワードであることにも注意してください。したがって、(既に正しく表示されているように)バックティックが必要です。列に別の単語を使用する方が便利な場合があります。
MySQLテーブルの重複を削除することは一般的な問題であり、通常、特定のニーズが伴います。誰かが興味を持っている場合は、ここ(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;
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)
ます。
これは大きなテーブルで機能します:
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)
これにより、列column_name
が主キーになり、その間すべてのエラーが無視されます。したがって、の値が重複する行を削除しますcolumn_name
。
ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);
これは基本的にテーブルをコピーして空にしてから、個別の値のみを元に戻すことで機能すると思いますが、大量のデータに対して実行する前にもう一度確認してください。
テーブルのカーボンコピーを作成します
oldtablenameのようなテーブルtemp_tableを作成します。temp_table select * from oldtablenameを挿入します。
元のテーブルを空にします
DELETE * oldtablenameから。
コピーされたテーブルからすべての個別の値を元のテーブルにコピーして戻します
INSERT oldtablename SELECT * from temp_table group by firstname、lastname、dob
一時テーブルを削除します。
テーブルを削除するtemp_table
区別したいaLLフィールドでグループ化する必要があります。
DELETE T2
FROM table_name T1
JOIN same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
それらをカウントし、削除クエリに制限を追加して1つだけにしておけば機能しますか?
たとえば、2つ以上ある場合は、次のようにクエリを記述します。
DELETE FROM table WHERE SID = 1 LIMIT 1;
テーブルから重複データを削除する場合、いくつかの基本的な手順があります。
これは完全なチュートリアルです:https : //blog.teamsql.io/deleting-duplicate-data-3541485b3473