我有一个带有唯一索引的条形码列的表。数据已经在每个条形码的末尾加载了额外的字符(-xx)以防止重复,但是一旦我去掉后缀,就会有很多重复。以下是数据样本:
itemnumber barcode
17912 2-14
18082 2-1
21870 2-10
29219 2-8
然后我创建了两个临时表,marty和manny,两者都带有itemnumber和剥离的条形码。因此,两个表都包含
itemnumber barcode
17912 2
18082 2
21870 2
29219 2
等
我尝试删除除marty表中条形码“2”的第一个条目(以及其他所有条形码)以外的所有条目。我希望然后用正确的第一个条目更新原始表,用户可以在应用程序中及时修复重复项。
所以,这是我的查询,除了每个条形码的marty表中的第一个条目
DELETE FROM marty
WHERE itemnumber NOT IN
(SELECT MIN(itemnumber) FROM manny GROUP BY barcode)
marty和manny有130,000行。查询花了24个小时,然后没有正确完成。与服务器的连接崩溃,查询未执行所有更新。
有没有更好的方法来解决这个问题,而不是我们的子查询,我认为这会导致延迟?而且,如果有这么多记录,那么小组也可能会减慢速度。
由于
答案 0 :(得分:2)
另一个变体:此变体在没有任何临时表的情况下可以删除重复项:
Delete m1
From Marty m1
join Marty m2
on m1.barcode = m2.barcode
and m1.itemnumber > m2.itemnumber
答案 1 :(得分:1)
使用IN
非常大的集合时,MySQL的速度非常慢。脚本替代:
使用脚本构建一个长itemnumber = X OR itemnumber = y OR itemnumber = z
子句(块大小~1000)和INSERT
匹配的行(即前一个查询中不会DELETE
d的行)进入一个新表,TRUNCATE
现有的并将新表的内容加载回旧INSERT INTO marty SELECT * FROM marty_tmp
。
您可能希望锁定该表或在最终TRUNCATE
,INSERT
的交易中运行。
修改强>
SELECT MIN(itemnumber) FROM manny GROUP BY barcode
,将结果存储在desiredItemNumbers数组INSERT INTO manny_tmp SELECT * FROM manny WHERE itemnumber = desiredItemNumbers[0] OR itemnumber = desiredItemNumbers[1] ...
。重新运行此查询,直到您用尽了desiredItemNumbers数组(n.b.最后一个查询可能少于1000个desiredItemNumbers)。DELETE
剩余的结果,因此交换marty
和marty_tmp
表的内容。TRUNCATE marty
INSERT INTO marty SELECT * FROM marty_tmp
答案 2 :(得分:1)
这是一个避免使用NOT IN
的两阶段方法。它也不使用临时表“manny”。首先,将“marty”加入到自身中以选择itemnumber!= min(itemnumber)的行。使用UPDATE
将这些行的barcode
设置为NULL
。第二次使用DELETE
然后删除在第一阶段标记的所有行。
对于此示例,我将“marty”的barcode
列拆分为两列;可以使用原始格式的表进行一些修改(需要动态分割列值)。
select * from marty;
+------------+---------+---------+
| itemnumber | barcode | subcode |
+------------+---------+---------+
| 17912 | 2 | 14 |
| 18082 | 2 | 1 |
| 21870 | 2 | 10 |
| 29219 | 2 | 8 |
| 30133 | 3 | 5 |
| 30134 | 3 | 7 |
| 30139 | 3 | 9 |
| 30142 | 3 | 12 |
+------------+---------+---------+
8 rows in set (0.00 sec)
UPDATE
(marty m1
JOIN
(SELECT barcode,
MIN(itemnumber) AS itemnumber
FROM marty
GROUP BY barcode) m2
USING(barcode))
SET m1.barcode = NULL WHERE m1.itemnumber != m2.itemnumber;
mysql> select * from marty;
+------------+---------+---------+
| itemnumber | barcode | subcode |
+------------+---------+---------+
| 17912 | 2 | 14 |
| 18082 | NULL | 1 |
| 21870 | NULL | 10 |
| 29219 | NULL | 8 |
| 30133 | 3 | 5 |
| 30134 | NULL | 7 |
| 30139 | NULL | 9 |
| 30142 | NULL | 12 |
+------------+---------+---------+
8 rows in set (0.00 sec)
DELETE FROM marty WHERE barcode IS NULL;
答案 3 :(得分:0)
如果您正在创建临时表,那么如何基于以下内容使用“INSERT INTO”或“CREATE TABLE ... AS ...”构建表:
SELECT MIN(itemnumber) AS itemnumber, barcode
FROM marty
GROUP BY barcode