【MySQL】測試MySQL表中安全刪除重復數據只保留一條的相關方法


第二篇文章測試說明
開發測試中,難免會存在一些重復行數據,因此常常會造成一些測試異常.
下面簡單測試mysql表刪除重復數據行的相關操作.
主要通過一下三個大標題來測試說明:
02.嘗試刪除dept_name重復的列
03 嘗試刪除多個字段(dept_name和db_source)都重復的字段!
04 是否可以使用兩重for循環來判斷是否存在重復行並進行刪除!

數據庫的表不要隨便刪除,需要刪除部分數據的話請事先備份成SQL,或者創建備份表.不然--
后端一時爽,運維火葬場.

01.建表

(隨手找來一個現成的表,直接拷貝出sql語句)
CREATE DATABASE IF NOT EXISTS cloudDB01;

USE clouddb01;

CREATE TABLE IF NOT EXISTS `dept` (
  `dept_no` BIGINT(20) NOT NULL AUTO_INCREMENT,
  `dept_name` VARCHAR(60) DEFAULT NULL,
  `db_source` VARCHAR(60) DEFAULT NULL,
  PRIMARY KEY (`dept_no`)
) ENGINE=INNODB AUTO_INCREMENT=278 DEFAULT CHARSET=utf8;
 /*插入dept表一系列數據*/
insert  into `dept`(`dept_no`,`dept_name`,`db_source`) values 
(1,'開發部','clouddb01'),
(2,'人事部','clouddb01'),
(3,'財務部','clouddb01'),
(4,'市場部','clouddb01'),
(5,'運維部','clouddb01'),
(6,'\'喝茶醬油部\'','clouddb01'),
(21,'開發部','clouddb01'),
(22,'人事部','clouddb01'),
(23,'財務部','clouddb01'),
(24,'市場部','clouddb01'),
(25,'運維部','clouddb01'),
(26,'\'喝茶醬油部\'','clouddb01');

02.嘗試刪除dept_name重復的列

也就是說,一個部門名只用占一行就可以了,多行的話豈不是浪費了!
  • 02.1.1.查詢存在dept_name存在重復的行
SELECT  d.dept_name
	FROM `dept` d
	GROUP BY d.`dept_name` 
	HAVING  COUNT(dept_name) > 1
  • 02.1.2.結果
    image.png
  • 02.2.1 把上面的表當做子表查出重復的整個行
SELECT *
FROM `dept` 
WHERE `dept_name` IN
(
      SELECT  d.dept_name
	FROM `dept` d
	GROUP BY d.`dept_name` 
	HAVING  COUNT(dept_name) > 1	
);  
  • 02.2.2 結果 (其實這里恰好就是整個表了)
    image.png
  • 02.3.1 上面的結果是不行的,刪除時不能都刪了,我們為了保留一個行,where條件需要再修改一下保留部門號(dept_no)最小的那行數據好了!
DELETE
FROM
  `dept`
WHERE `dept_name` IN

  (SELECT
    dept_name
  FROM
    `dept` 
  GROUP BY `dept_name`
  HAVING COUNT(dept_name) > 1)
  
  AND `dept_no` NOT IN 
  
  (SELECT
    MIN(dept_no)
  FROM
    `dept` 
  GROUP BY `dept_name`
  HAVING COUNT(dept_name) > 1);
  • 02.3.2 結果 : 執行出現問題;
    image.png
  • 02.3.3 那是什么原因呢?原因:筆者的數據庫安全模式較高,為REPEATABLE-READ(可重復讀)級別,此模式下可以解決臟讀 和 不可重復讀 (mysql默認的);
    錯誤代碼:1093,意思就是mysql不允許在查詢表的同時對這個表進行刪除更新操作是不安全的.

    image.png
    • 02.3.4 那可怎么辦?除了降級以外還能怎么辦?
      Duang!!Duang!!Duang!!Duang!!
      再來一個副本表"dept2",同時還可以起到備份的作用! 創建的sql在最上面,都在dept后面加個2即可!
      dept2.png

-02.3.5 Show Time!是不是恍然大悟了!

DELETE
FROM
  `dept`
WHERE `dept_name` IN

  (SELECT
    dept_name
  FROM
    `dept2` 
  GROUP BY `dept_name`
  HAVING COUNT(dept_name) > 1)
  
  AND `dept_no` NOT IN 
  
  (SELECT
    MIN(dept_no)
  FROM
    `dept2` 
  GROUP BY `dept_name`
  HAVING COUNT(dept_name) > 1);

-02.3.6 回頭看,不曾走遠,dept表中dept_name重復的行已經沒了!!
image.png

03 嘗試刪除多個字段(dept_name和db_source)都重復的字段!

目的也就是一個部門實體用這兩個字段就可以清楚地區分出來,如何任意兩行數據中存在dept_name和db_source都重復的話,那么必定有一項為重復的沒有意義的! 既然沒有意義,那就刪除了!
  • 03.1.1 清空dept表和備份表dept2,dept表的sql如下,dept2的sql簡單把下面的表名改一下即可
    注意,人事部和喝茶醬油部這兩個的db_source列是油變動的,不然跟上面的表就一模一樣了!
/*清空dept表,以及重置自增的主鍵*/
TRUNCATE dept;
/*插入dept表一系列數據*/
INSERT  INTO `dept`(`dept_no`,`dept_name`,`db_source`) VALUES 
(1,'開發部','clouddb01'),
(2,'人事部','clouddb02'),
(3,'財務部','clouddb01'),
(4,'市場部','clouddb01'),
(5,'運維部','clouddb01'),
(6,'\'喝茶醬油部\'','clouddb02'),
(21,'開發部','clouddb01'),
(22,'人事部','clouddb01'),
(23,'財務部','clouddb01'),
(24,'市場部','clouddb01'),
(25,'運維部','clouddb01'),
(26,'\'喝茶醬油部\'','clouddb01');
  • 03.1.2 現有dept/dept2表數據
    image.png
  • 03.2.1 比葫蘆畫瓢,使用上面的方法試試!同樣,如果存在兩個列數據重復的行的話,只保留dept_no最小的哪行數據!
DELETE
FROM
  `dept`
WHERE `dept_name` IN
        /*篩選出存在多列重復的*/
  (SELECT
    dept_name
  FROM
    `dept2` 
  GROUP BY `dept_name`,db_source
  HAVING COUNT(dept_name) > 1)
      /**保留dept_no最小的那行數據*/
  AND `dept_no` NOT IN 
  
  (SELECT
    MIN(dept_no)
  FROM
    `dept2` 
  GROUP BY `dept_name`
  HAVING COUNT(dept_name) > 1);
  • 03.2.2 結果怎么樣 : 符合預期結果
    image.png

    • 03.3.1 單獨執行第一個子表中的內容,發現正好篩選出了四個部門,沒有人事部和喝茶醬油部這兩個.
      想想,GROUP BY X, Y意思是將所有具有相同X字段值和Y字段值的記錄放到一個分組里。
      這里的是 GROUP BY dept_name,db_source ,故只選出XY兩個字段都相同的才可以放到一塊來.
      image.png

04 是否可以使用兩重for循環來判斷是否存在重復行並進行刪除!

  • 就像一維數組一樣,進行刪除操作!
  • mysql貌似也支持寫for循環!不過.....用Java不更方便吧!
  • 貌似還真可以, 先把所有mysql表中的數據取出來轉換成List ,然后跑兩重for循環遍歷List ,如果判斷出兩個實體符合重復的條件,則一定有一個實體是多余的,則從數據庫中移除對應的記錄(行)即可!
  • 暴力大法好! 時間上應該不分上下!
  • 我都想好了實現步驟,
    1>取數據: MybatisPlus的baseMapper.selectList() ;
    2>for兩重判斷實體是否相等,
    2> 如果存在則刪除一個即可: baseMapper.deleteById(xxxx) / 同時移除一個實體 兩個操作即可.
  • 其他方法也可以喲!
  • 未完待續!!


免責聲明!

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



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