删除与 MySQL 中的上一行没有区别的行
Remove rows that do not differ from the previous row in MySQL
假设我有一个 table 来记录我的数据库随时间的变化:
TimeOfChange FieldA FieldB FieldC
-------------------------------------
2019-01-01 A1 B1 C1 /*(R1)*/
2019-01-02 A2 B2 C1 /*(R2)*/
2019-01-03 A2 B2 C1 /*(R3)*/
2019-01-05 A1 B1 C2 /*(R4)*/
2019-01-07 A1 B1 C1 /*(R5)*/
我的数据库有很多行没有发生重大变化,例如行 (R3) 与 (R2) 相同。
我想删除这些行。我找到了很多关于如何使用通用 table 表达式从 table 中删除重复行的参考资料。因此可以删除重复的(忽略 TimeOfChange 列)行。但这也将删除 (R5),因为它与 R1 相同。当按 TimeOfChange 列排序时,我只想删除与前一行具有相同 ABC 值的行。我该怎么做?
编辑:您可以假设 TimeOfChange 值都是唯一的
假设 TimeOfChange 是唯一的,你可以这样做:
delete
from data
where TimeOfChange in (
select TimeOfChange
from (
select d2.TimeOfChange
from data d1
join data d2
where d2.TimeOfChange in (
select min(x.TimeOfChange)
from data x
where x.TimeOfChange>d1.TimeOfChange
) and d1.FieldA=d2.FieldA and d1.FieldB=d2.FieldB and d1.FieldC=d2.FieldC
) as q
);
因此您首先要确定哪些行是 "next",然后检查 "next" 是否与 "current" 具有相同的值。对于那些 "next" 将形成一个结果集,你想在 DELETE
中使用。 select * from data
是为了避免在 DELETE
和子查询中重用 table。
如果将逻辑分离到存储过程中并将要删除的行的 ID 存储到临时文件中,您可能会获得更好的性能 table。
假设您的意思是 "when the same A, B, C occurred on the most recent day prior that had any data",这应该可用于识别需要删除的行:
SELECT t2.TimeOfChange, t2.FieldA, t2.FieldB, t2.FieldC
FROM (
SELECT tMain.TimeOfChange, tMain.FieldA, tMain.FieldB, tMain.FieldC
, MAX(tPrev.TimeOfChange) AS prevTimeOfChange
FROM t AS tMain
LEFT JOIN t AS tPrev ON t.TimeOfChange> tPrev.TimeOfChange
GROUP BY tMain.TimeOfChange, tMain.FieldA, tMain.FieldB, tMain.FieldC
) AS t2
INNER JOIN t AS tPrev2
ON t2.prevTimeOfChange = tPrev2.TimeOfChange
AND t2.FieldA = tPrev2.FieldA
AND t2.FieldB = tPrev2.FieldB
AND t2.FieldC = tPrev2.FieldC
这可以在 DELETE 中使用,通过一些间接的方式强制创建一个临时文件 table。
DELETE td
FROM t AS td
WHERE (td.TimeOfChange, td.FieldA, td.FieldB, td.FieldC)
IN (SELECT * FROM ([the query above]) AS tt) -- Yes, you have to wrap the query from above in a select * so mysql will not reject it.
;
然而,在走到这一步之后,会发生什么......
2019-01-01 A1 B1 C1
2019-01-02 A2 B2 C1
2019-01-03 A2 B2 C1
2019-01-04 A1 B1 C2
2019-01-05 A1 B1 C3
2019-01-05 A1 B1 C1
2019-01-06 A1 B1 C3
2019-01-07 A1 B1 C1
变成
2019-01-01 A1 B1 C1
2019-01-02 A2 B2 C1
2019-01-04 A1 B1 C2
2019-01-05 A1 B1 C3
2019-01-05 A1 B1 C1
2019-01-07 A1 B1 C1
现在是否需要进行第二遍删除 2019-01-07
条目?
您要重复 运行 查询直到没有行受到影响吗?
假设我有一个 table 来记录我的数据库随时间的变化:
TimeOfChange FieldA FieldB FieldC
-------------------------------------
2019-01-01 A1 B1 C1 /*(R1)*/
2019-01-02 A2 B2 C1 /*(R2)*/
2019-01-03 A2 B2 C1 /*(R3)*/
2019-01-05 A1 B1 C2 /*(R4)*/
2019-01-07 A1 B1 C1 /*(R5)*/
我的数据库有很多行没有发生重大变化,例如行 (R3) 与 (R2) 相同。 我想删除这些行。我找到了很多关于如何使用通用 table 表达式从 table 中删除重复行的参考资料。因此可以删除重复的(忽略 TimeOfChange 列)行。但这也将删除 (R5),因为它与 R1 相同。当按 TimeOfChange 列排序时,我只想删除与前一行具有相同 ABC 值的行。我该怎么做?
编辑:您可以假设 TimeOfChange 值都是唯一的
假设 TimeOfChange 是唯一的,你可以这样做:
delete
from data
where TimeOfChange in (
select TimeOfChange
from (
select d2.TimeOfChange
from data d1
join data d2
where d2.TimeOfChange in (
select min(x.TimeOfChange)
from data x
where x.TimeOfChange>d1.TimeOfChange
) and d1.FieldA=d2.FieldA and d1.FieldB=d2.FieldB and d1.FieldC=d2.FieldC
) as q
);
因此您首先要确定哪些行是 "next",然后检查 "next" 是否与 "current" 具有相同的值。对于那些 "next" 将形成一个结果集,你想在 DELETE
中使用。 select * from data
是为了避免在 DELETE
和子查询中重用 table。
如果将逻辑分离到存储过程中并将要删除的行的 ID 存储到临时文件中,您可能会获得更好的性能 table。
假设您的意思是 "when the same A, B, C occurred on the most recent day prior that had any data",这应该可用于识别需要删除的行:
SELECT t2.TimeOfChange, t2.FieldA, t2.FieldB, t2.FieldC
FROM (
SELECT tMain.TimeOfChange, tMain.FieldA, tMain.FieldB, tMain.FieldC
, MAX(tPrev.TimeOfChange) AS prevTimeOfChange
FROM t AS tMain
LEFT JOIN t AS tPrev ON t.TimeOfChange> tPrev.TimeOfChange
GROUP BY tMain.TimeOfChange, tMain.FieldA, tMain.FieldB, tMain.FieldC
) AS t2
INNER JOIN t AS tPrev2
ON t2.prevTimeOfChange = tPrev2.TimeOfChange
AND t2.FieldA = tPrev2.FieldA
AND t2.FieldB = tPrev2.FieldB
AND t2.FieldC = tPrev2.FieldC
这可以在 DELETE 中使用,通过一些间接的方式强制创建一个临时文件 table。
DELETE td
FROM t AS td
WHERE (td.TimeOfChange, td.FieldA, td.FieldB, td.FieldC)
IN (SELECT * FROM ([the query above]) AS tt) -- Yes, you have to wrap the query from above in a select * so mysql will not reject it.
;
然而,在走到这一步之后,会发生什么......
2019-01-01 A1 B1 C1
2019-01-02 A2 B2 C1
2019-01-03 A2 B2 C1
2019-01-04 A1 B1 C2
2019-01-05 A1 B1 C3
2019-01-05 A1 B1 C1
2019-01-06 A1 B1 C3
2019-01-07 A1 B1 C1
变成
2019-01-01 A1 B1 C1
2019-01-02 A2 B2 C1
2019-01-04 A1 B1 C2
2019-01-05 A1 B1 C3
2019-01-05 A1 B1 C1
2019-01-07 A1 B1 C1
现在是否需要进行第二遍删除 2019-01-07
条目?
您要重复 运行 查询直到没有行受到影响吗?