1.問題引入
假設一個場景,一張用戶表,包含3個字段。id,identity_id,name?,F在身份證號identity_id和姓名name有很多重復的數據,需要刪除只保留一條有效數據。
2.模擬環(huán)境
1.登入mysql數據庫,創(chuàng)建一個單獨的測試數據庫mysql_exercise
create database mysql_exercise charset utf8;
2.創(chuàng)建用戶表users
create table users(
id int auto_increment primary key,
identity_id varchar(20),
name varchar(20) not null
);
![](/d/20211017/f089686168ee8116b43af206ed0abf07.gif)
3.插入測試數據
insert into users values(0,'620616199409206512','張三'),
(0,'620616199409206512','張三'),
(0,'62062619930920651X','李四'),
(0,'62062619930920651X','李四'),
(0,'620622199101206211','王五'),
(0,'620622199101206211','王五'),
(0,'322235199909116233','趙六');
可以多執(zhí)行幾次,生成較多重復數據。
![](/d/20211017/3a3b53d647adc623f0d5cee19e88b6d6.gif)
4.解決思路
(1)根據身份證號和name進行分組;
(2)取出分組后的最大id(或最小id);
(3)刪除除最大(或最小)id以外的其他字段;
5.第一次嘗試(失敗!!!)
delete from users where id not in (select max(id) from users group by identity_id,name);
報錯:
1093 (HY000): You can't specify target table 'users' for update in FROM clause
![](/d/20211017/593d9e3f76b6834e041a705b6c34e6b5.gif)
因為在MYSQL里,不能先select一個表的記錄,再按此條件進行更新和刪除同一個表的記錄。
解決辦法是,將select得到的結果,再通過中間表select一遍,這樣就規(guī)避了錯誤,
這個問題只出現于mysql,mssql和oracle不會出現此問題。
所以我們可以先將括號里面的sql語句先拿出來,先查到最大(或最?。﹊d。
select max_id from (select max(id) as max_id from users group by identity_id,name);
接著,又報錯了!??!
ERROR 1248 (42000): Every derived table must have its own alias
意思是說:提示說每一個衍生出來的表,必須要有自己的別名!
執(zhí)行子查詢的時候,外層查詢會將內層的查詢當做一張表來處理,所以我們需要給內層的查詢加上別名
![](/d/20211017/a9cf46edcc028ac8eb807df19df96205.gif)
繼續(xù)更正:
給查詢到的最大(或最小id)結果當做一張新的表,起別名t,并查詢t.mix_id。
select t.max_id from (select max(id) as max_id from users group by identity_id,name) as t;
可以成功查到最大(或最?。﹊d了,如下圖:
![](/d/20211017/998ad6b0227245135bab6fc891eb7c8b.gif)
6.第二次嘗試(成功?。。。?/strong>
delete from users where id not in (
select t.max_id from
(select max(id) as max_id from users group by identity_id,name) as t
);
執(zhí)行結果:
![](/d/20211017/e976d912746b0b8930f4d4d29d6f8828.gif)
成功將重復的數據刪除,只保留了最后一次增加的記錄。同理也可以保留第一次添加的記錄(即刪除每個分組里面除最小id以外的其他條記錄)
3.知識拓展一:更新數據
其他場景應用:要將用戶表user_info里名字(name)為空字符串("")的用戶的狀態(tài)(status)改成"0"
update user_info set status='0' where user_id in (select user_id from user_info where name='')
同樣報了如下錯誤:
You can't specify target table ‘user_info' for update in FROM clause
因為在MYSQL里,不能先select一個表的記錄,再按此條件進行更新和刪除同一個表的記錄,解決辦法是,將select得到的結果,再通過中間表select一遍,這樣就規(guī)避了錯誤。
以下兩種均可?。?!
update user_info set status='0' where user_id in
(select user_id from (select user_id from user_info where name = '') t1);
下面這種也可,細微差別,別名可帶as可不帶,t1.user_id 直接和內層的user_id對應也可以。
update user_info set status='0' where user_id in
(select t1.user_id from (select user_id from user_info where name='') as t1);
3.1 分步驟解析
(1)將以下查詢結果作為中間表:
select user_id from user_info where name='';
(2)再查詢一遍中間表作為結果集:
select user_id from (select user_id from user_info where name='') as t;
(3)更新數據
update user_info set status='0' where user_id in
(select user_id from (select user_id from user_info where name='') as t1);
4.拓展練習:刪除重復數據
編寫一個 SQL 查詢,來刪除 Person 表中所有重復的電子郵箱,重復的郵箱里只保留 Id 最小 的那個。
+----+------------------+
| Id | Email |
+----+------------------+
| 1 | john@example.com |
| 2 | bob@example.com |
| 3 | john@example.com |
+----+------------------+
Id 是這個表的主鍵。
例如,在運行你的查詢語句之后,上面的 Person 表應返回以下幾行:
+----+------------------+
| Id | Email |
+----+------------------+
| 1 | john@example.com |
| 2 | bob@example.com |
+----+------------------+
解答一:
delete from Person where Id not in (
select t.min_id from (
select min(Id) as min_id from Person group by Email
) as t
);
解答二:
delete p1 from
Person as p1,Person as p2
where p1.Email=p2.Email and p1.Id > p2.Id;
總結
到此這篇關于mysql數據庫刪除重復數據的方法只保留一條的文章就介紹到這了,更多相關mysql刪除重復數據內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- MyBatis批量插入/修改/刪除MySql數據
- mysql利用mysqlbinlog命令恢復誤刪除數據的實現
- mysql5.7.33誤刪除ibdata文件找回數據的方法
- mysql 大表批量刪除大量數據的實現方法
- 淺談為什么MySQL不建議delete刪除數據
- Python批量刪除mysql中千萬級大量數據的腳本分享
- Mysql刪除數據以及數據表的方法實例
- MySQL刪除數據,表文件大小依然沒變的原因
- MySQL 快速刪除大量數據(千萬級別)的幾種實踐方案詳解
- MySQL Delete 刪數據后磁盤空間未釋放的原因