sql如何去除重復的數據-好點的


sql如何去除重復的數據-好點的

之前寫的mysql去重多個字段,是不太對的。因為我是用distinct (xm,phone)去重,然后將xm,phone為唯一的數據插入新表,但是數據中有三個字段:id,xm,phone,我上一種方法是沒法插入id的,因為xm,phone重復的加上id,就變成不重復的了。

例子:

id nam  phone
1 張三 123
2 張三 123
這本來是重復的數據,但是如果distinc * 就成了兩條不重復的數據了,因為前面的id不重復
INSERT into chongfubiao_quchong_copy (id, nam, phone)
select distinct *  from chongfubiao_quchong ;

而下面這種又會有語法錯誤[Err] ERROR: INSERT has more target columns than expressions;因為查詢的是兩欄插入的是三欄

INSERT into chongfubiao_quchong_copy1 (id, nam, phone)
select distinct nam,phone  from chongfubiao_quchong ;

沒法處理。然后從網上搜索,查到下面答案:

sql中如何刪除一個表中重復的記錄? https://zhidao.baidu.com/question/331566667.html

[SQL]delete from jck_rk_info_quchong_endwhere sfzh in (select sfzh from jck_rk_info_quchong_end group by sfzh having count(sfzh) > 1)and bh not in (select min(bh) from jck_rk_info_quchong_end group by bh having count(bh )>1)
時間: 14.839s
受影響的行: 2026251

不是很好,因為把重復的都去除,連本身也去除。 要實現的是,重復數據中多余的數據刪除,只保留重復數據的一條數據

 

又搜到一個和上面的語句差不多,不知道為啥,怎么判斷語句的時候都是min呢?都是not in 呢? 反正我都沒有成功?原因如下:

#插入重復的的數據 多個值去重后的一個 # 這個語句是有問題的,主要在於not in min(),只能篩選出最小的那個,比如有 1,2,3,后續保留的是2,3。還是有兩個重復的,而且只能去除一個,不是每個重復的去除一個(1000個重復的去除1000個)。是所有重復的中去除一個(1000個重復的去除1個)。

INSERT into quchongcharu_copy (id,name,sfzh)select * from quchongcharuwheresfzh in (select sfzh from quchongcharu group by sfzh having count(sfzh) > 1)and id not in ( select min(id) from quchongcharu group by id having count(id )> 1);

 

既然大家都用這個實現了去重。而不是把重復的本身也去除掉,可能是我使用有點問題。下面這個也是同樣的語句沒法,但是畫的圖好,幫助我實現了我的需求。

思路來源,和其他分享一樣都是用的max,不能實現我的需求。不過用圖形象,啟發了我。我試了下min也不行,后來試了用in 不用not in就可以了。https://blog.csdn.net/wumian0123/article/details/81539631

修改后的查詢語句如下-對重復的語句進行去重僅保留本身:

SELECT id,name,sfzh
FROM quchongcharu
WHERE
(sfzh , name) IN
(SELECT sfzh,name FROM quchongcharu
GROUP BY sfzh, name
HAVING COUNT(*)>1)
AND
id IN
(SELECT min(id) FROM quchongcharu
GROUP BY sfzh,name
HAVING COUNT(*) > 1)

數據

image-20201028233122225

查詢出重復數據的本身

image-20201028233210137

由於1 張三 123、1 張三 123數據id也重復,然后后面的and判斷語句是根據id篩選本身的,沒法排除,其余均可以。關於id一般都是編號,每個人的id都不是一樣的,所以實際場合應該符合條件(但是這個問題現在仍然存在,后續想解決)

語句解析(感覺好的點在於and 還有 in 還有 min最小值保證唯一)

上面語句在於where后的篩選語句
# 這句是統計出sfzh,name分組后,分組的sfzh,name出現數目大於1的即為重復
(sfzh , name) IN
(SELECT sfzh,name FROM quchongcharu
GROUP BY sfzh, name
HAVING COUNT(*)>1)
中間and是在上面統計出來的數據做交集。上面統計出很多重復數據
如:
1 李四 124
6 李四 124
下面
id IN
(SELECT min(id) FROM quchongcharu
GROUP BY sfzh,name
HAVING COUNT(*) > 1)
下面的語句也是出現大於1的重復,但是查詢的是min(id),最小值只有一個,所以就保證唯一,不重復了:也就是id= 1 (所以我想不懂很多博客寫的 not in max值,那如果 id為 1、2、4,not in 4 ,不是還有1、2嗎?而且  not in 一個值,不是還有很多嗎,不如in 一個值來的好啊)
1 李四 124

現在想了想,既然id in min 就能保證唯一然后后面的語句是查詢重復的。那么可以不用上面的and了。

簡化版查詢去重語句

SELECT id,name,sfzh
FROM quchongcharu
where
id IN
(SELECT min(id) FROM quchongcharu
GROUP BY sfzh,name
HAVING COUNT(*) > 1)

image-20201028234357709

結果是一樣的。

上面的語句只是找出了重復數據的本身,還有不重復數據無需去重,也需要合並一下

不重復的語句用

(sfzh , name) IN
(SELECT quchongcharu.sfzh,quchongcharu.name
FROM quchongcharu
GROUP BY quchongcharu.sfzh,quchongcharu.name
HAVING COUNT(*)=1)

查詢

因為都得包括所以取並集,用or,

SELECT id,name,sfzh
FROM quchongcharu
where
id IN
(SELECT min(id) FROM quchongcharu
GROUP BY sfzh,name
HAVING COUNT(*) > 1)

or

(sfzh , name) IN
(SELECT quchongcharu.sfzh,quchongcharu.name
FROM quchongcharu
GROUP BY quchongcharu.sfzh,quchongcharu.name
HAVING COUNT(*)=1) ;

image-20201028234708108

然后可以更新到一張新表中。

insert into 新表 (id,name,sfzh) 上面sql

 

雖然id實際生活中不會重復,但是也有可能會重復,如果不設置主鍵,而且上面的也看這不好看。 1 張三 123 確實是重復的,沒有去重。 雖然把

image-20201028234940250

其他id的張三123去重了。

關於查詢到的下述數據的去重

image-20201028234357709

雖然可以如下操作

image-20201029000529134

但是是row的格式().不是數據表

搜了下distinct的原理,沒打搞懂,但是說和group by相似,先排序,然后。。。

https://blog.csdn.net/xpzhang123/article/details/50175755?utm_source=copy

就去搜group by的用法:

image-20201029003157746

果然好用。order by是排序來的。

之前用group by order by 時,老是顯示這一組的一個。(很煩,得另外處理)現在group by 和 order by 幫重復的 1 張三 123 去了重

select id,sfzh,name from quchongcharu_copy1 group by id,sfzh,name ORDER BY id,sfzh,name;
select * from quchongcharu_copy1 group by id,sfzh,name ORDER BY id,sfzh,name;

上述的問題解決語句

SELECT *
FROM quchongcharu

where
id IN
(SELECT min(id) FROM quchongcharu
GROUP BY sfzh,name
HAVING COUNT(*) > 1)

group by id,sfzh,name ORDER BY id,sfzh,name

image-20201029003828823

最終版去重語句 重復的都可以去的保留本身;還有保留本不重復的;

SELECT *
FROM quchongcharu

where
id IN
(SELECT min(id) FROM quchongcharu
GROUP BY sfzh,name
HAVING COUNT(*) > 1)

or

(sfzh , name) IN
(SELECT quchongcharu.sfzh,quchongcharu.name
FROM quchongcharu
GROUP BY quchongcharu.sfzh,quchongcharu.name
HAVING COUNT(*)=1)

group by id,sfzh,name ORDER BY id,sfzh,name
---最后一行 id,sfzh,name 替換 需要包含所有的列名 ,測試用例只有三列

image-20201029004028672

在看一眼源表:

image-20201029004120140

 

 

當有時有用上面最終版去重語句但是查不出來,但是去了語句中的空格就好了。在調回有空格的,也能執行了。不知道為啥

[Err] ERROR:  syntax error at or near ""
LINE 30: ;
SELECT *
FROM quchongcharu

where
id IN
(SELECT min(id) FROM quchongcharu
GROUP BY sfzh,name
HAVING COUNT(*) > 1)

or

(sfzh , name) IN
(SELECT sfzh,name
FROM quchongcharu
GROUP BY sfzh,name
HAVING COUNT(*)=1)

group by id,sfzh,name ORDER BY id,sfzh,name  
--- 這邊的 id,sfzh,name 是所有的列名, 如果不全報錯,缺少排列的列名
---[Err] ERROR: column "•.pxxx" must appear in the GROUP BY clause or be used in an aggregate function

好麻煩呀!等着寫個簡單點的。

 

# 最新去重語句

發現去重主要作用是主要是 group by ,是一樣的效果,上面having 在group by 是重復了。

簡化如下 根據idcard 去重 去idcard唯一,取數據bh最下的那條數據 。 得到了 取最小的bh 所有的idcard,就不會重復了

這樣

select * from gjk_rsj_rkxx_quchong
where
idcard in (
SELECT idcard FROM gjk_rsj_rkxx_quchong
GROUP BY idcard
HAVING COUNT(idcard) >= 1 )  
and
bh in ( SELECT min(bh) FROM gjk_rsj_rkxx_quchong
GROUP BY idcard
HAVING COUNT(idcard) >= 1);

這樣都行

select count(*) from gjk_rsj_rkxx_quchong
where
idcard
in (
SELECT idcard FROM gjk_rsj_rkxx_quchong
GROUP BY idcard
)  
and
bh
in ( SELECT min(bh) FROM gjk_rsj_rkxx_quchong
GROUP BY idcard
);

然后再把上面查到的數據查到要更新的表就行了

INSERT into gjk_rsj_rkxx_quchong1 (idcard,name,sbbh,sex,nation,birthdate,education,face,marriage,zyjszw,gjzyzgdj,hkxz,grzt,hkszdmc,jzdmc,phone,txdz,yzbm,dzxx,jysydjh,byxx,bysj,sxzy,s_createtime,s_last_updatetime)
select ......

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM