固有のid
およびemail
フィールドがあります。メールが重複します。すべての重複の1つの電子メールアドレスのみを保持しますが、最新のid
(最後に挿入されたレコード)を使用します。
どうすればこれを達成できますか?
テーブルtest
に次のデータが含まれているとします。
select id, email
from test;
ID EMAIL
---------------------- --------------------
1 aaa
2 bbb
3 ccc
4 bbb
5 ddd
6 eee
7 aaa
8 aaa
9 eee
そのため、繰り返されるメールをすべて検索し、最新のIDを除いてすべて削除する必要があります。
この場合、aaa
、bbb
、eee
が繰り返されているため、ID 1、7、2、6を削除します。
これを行うには、最初にすべての繰り返しメールを見つける必要があります。
select email
from test
group by email
having count(*) > 1;
EMAIL
--------------------
aaa
bbb
eee
次に、このデータセットから、これらの繰り返しメールのそれぞれの最新IDを見つける必要があります。
select max(id) as lastId, email
from test
where email in (
select email
from test
group by email
having count(*) > 1
)
group by email;
LASTID EMAIL
---------------------- --------------------
8 aaa
4 bbb
9 eee
最後に、LASTIDより小さいIDを持つこれらの電子メールをすべて削除できます。したがって、解決策は次のとおりです。
delete test
from test
inner join (
select max(id) as lastId, email
from test
where email in (
select email
from test
group by email
having count(*) > 1
)
group by email
) duplic on duplic.email = test.email
where test.id < duplic.lastId;
現在、このマシンにmySqlをインストールしていませんが、動作するはずです。
上記の削除は機能しますが、より最適化されたバージョンが見つかりました:
delete test
from test
inner join (
select max(id) as lastId, email
from test
group by email
having count(*) > 1) duplic on duplic.email = test.email
where test.id < duplic.lastId;
最も古い重複、つまり1、7、2、6が削除されることがわかります。
select * from test;
+----+-------+
| id | email |
+----+-------+
| 3 | ccc |
| 4 | bbb |
| 5 | ddd |
| 8 | aaa |
| 9 | eee |
+----+-------+
別のバージョンは、 Rene Limon によって提供される削除です。
delete from test
where id not in (
select max(id)
from test
group by email)
正しい方法は
DELETE FROM `tablename`
WHERE id NOT IN (
SELECT * FROM (
SELECT MAX(id) FROM tablename
GROUP BY name
)
)
この方法を試してください
DELETE t1 FROM test t1, test t2
WHERE t1.id > t2.id AND t1.email = t2.email
私は個人的に上位2票の回答に問題がありました。これは最もクリーンなソリューションではありませんが、一時テーブルを利用して、MySQLが同じテーブルへの結合による削除で抱えているすべての問題を回避できます。
CREATE TEMPORARY TABLE deleteRows;
SELECT MIN(id) as id FROM myTable GROUP BY myTable.email;
DELETE FROM myTable
WHERE id NOT IN (SELECT id FROM deleteRows);
最適化されたバージョンは、スイートでエレガントなコードの1つであり、比較がDATETIME列で実行された場合でも、魅力的なように機能します。これはスクリプトで使用したもので、各EmployeeIDの最新の契約終了日を検索していました。
DELETE CurrentContractData
FROM CurrentContractData
INNER JOIN (
SELECT
EmployeeID,
PeriodofPerformanceStartDate,
max(PeriodofPerformanceEndDate) as lastDate,
ContractID
FROM CurrentContractData
GROUP BY EmployeeID
HAVING COUNT(*) > 1) Duplicate on Duplicate.EmployeeID = CurrentContractData.EmployeeID
WHERE CurrentContractData.PeriodofPerformanceEndDate < Duplicate.lastDate;
どうもありがとう!