複数列が同じ値のレコードが重複するテーブルのデータを1つだけ削除フラグをOFFにしたい。
HAVING count(*) > 1 を実行したくない。count(*) を実行してパフォーマンス劣化が心配だからである。
そんなに良いパフォーマンスではないかもしれないが以下のように考えてみた。
しかし、やっぱり遅いだろう。
(サンプル)
テーブルの定義、
DELIMITER //
DROP TABLE IF EXISTS gamma
//
CREATE TABLE gamma (
id INT NOT NULL AUTO_INCREMENT
, item_name VARCHAR(20) NOT NULL
, price INT
, mount INT
, memo VARCHAR(32)
, start_at DATE
, end_at DATE
, delete_flg INT
, PRIMARY KEY (id) )
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin
//
DELIMITER ;
「目的」
このテーブルの中で、id と mount 以外の列の値が、重複するレコードに、delete_flg = 1 にする。
1つの組み合わせだけ、delete_flg = 0 にする。
(データは、全て delete_flg = 0 になっていたとする)
方法は、以下のようなクエリの結果で delete_flg = 1 にすべきレコードの id を求めることで、
NULL のカラムを考慮する。
SELECT
x.id
FROM
(SELECT id,
CONCAT(item_name, '-', COALESCE(price, 'NULL'), '-', COALESCE(memo, 'NULL'), '-'
, COALESCE(start_at, 'NULL'), '-', COALESCE(end_at, 'NULL'), '-', delete_flg) AS catdata
FROM gamma
WHERE delete_flg = 0) x
INNER JOIN
(SELECT MAX(id) AS id,
CONCAT(item_name, '-', COALESCE(price, 'NULL'), '-', COALESCE(memo, 'NULL'), '-'
, COALESCE(start_at, 'NULL'), '-', COALESCE(end_at, 'NULL'), '-', delete_flg) AS catdata
FROM gamma
WHERE delete_flg = 0
GROUP BY catdata
HAVING COUNT(catdata) > 1) y
ON x.catdata = y.catdata
WHERE x.id <> y.id
ストアドプロシジャで以下のように定義する。
DELIMITER //
DROP PROCEDURE IF EXISTS sp_gamma_cleansing
//
CREATE PROCEDURE sp_gamma_cleansing()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE target_id INT;
-- カーソル定義
DECLARE c1 CURSOR FOR
SELECT x.id FROM
(SELECT id, CONCAT(item_name,'-',COALESCE(price,'NULL'),'-',COALESCE(memo,'NULL'),'-',COALESCE(start_at,'NULL')
,'-',COALESCE(end_at,'NULL'),'-',delete_flg ) AS catdata
FROM gamma WHERE delete_flg = 0) x
INNER JOIN
(SELECT MAX(id) AS id, CONCAT(item_name,'-',COALESCE(price,'NULL'),'-',COALESCE(memo,'NULL'),'-',COALESCE(start_at,'NULL')
,'-',COALESCE(end_at,'NULL'),'-',delete_flg ) AS catdata
FROM gamma WHERE delete_flg = 0
GROUP BY catdata HAVING COUNT(catdata) > 1 ) y
ON x.catdata = y.catdata
WHERE x.id <> y.id ;
-- ハンドラ宣言
DECLARE EXIT HANDLER FOR NOT FOUND SET done = 0;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN c1;
REPEAT
FETCH c1 INTO target_id;
IF NOT done THEN
UPDATE gamma SET delete_flg = 1 WHERE id = target_id;
END IF;
UNTIL done END REPEAT;
CLOSE c1;
END
//
DELIMITER ;
実行は、call sp_gamma_cleansing();
ストアド実行後の検証は、以下クエリで0件であること。
SELECT MAX(id)
, CONCAT(item_name,'-',COALESCE(price,'NULL'),'-',COALESCE(memo,'NULL'),'-',COALESCE(start_at,'NULL')
,'-',COALESCE(end_at,'NULL'),'-',delete_flg ) AS catdata
FROM gamma WHERE delete_flg = 0
GROUP BY catdata HAVING COUNT(catdata) > 1