【问题标题】:Delete rows where date is not minimum删除日期不是最小值的行
【发布时间】:2021-12-23 10:37:13
【问题描述】:

我有一个表(结构如下),我需要通过删除每个 Object_ID 的行来清理它:

WHERE Current_Step is NULL and Change = 'change' 
and Date_of_Change <> MIN(Date_of_Change)

也就是说,我只需要为每个Object_ID 留下具有最​​短日期的行。

表格示例

Object_ID Current_Step Change Date_of_Change
0025307 NULL change 16.11.2021
0025307 NULL change 19.11.2021
0025307 NULL change 19.11.2021

我正在使用 MS SQL。 没有主键。 所有列都是VARCHAR,除了Date_of_ChangeDATE 类型。

我需要清理此表的原因是因为源查询正在检查 IF NULL = NULL 然后将这些状态更改标记为已更改,即使它们没有更改,它也被错误地填充。所以我需要将值恢复到它们被更改的原始日期,因为如果它们仍然具有 NULL 值,则意味着状态没有发生实际变化。

期望的行为

我尝试识别需要保留的行:

SELECT [Object_ID]
      ,MIN([Date_of_Change])
FROM table
WHERE [Current_Step] IS NULL 
AND [Change] = 'change'
GROUP BY Object_ID

我只需要删除具有相同 Object_ID 且 Date_of_Change 不等于上述查询中标识的其他行。

【问题讨论】:

    标签: sql sql-server sql-delete


    【解决方案1】:

    像我在下面的“Table1223”上一样加入同一张桌子。

    例子:

    DELETE tbl 
    FROM Table1223 tbl
    JOIN (SELECT * FROM Table1223) objID
        ON objID.Object_ID = tbl.Object_ID
    WHERE tbl.Date_of_Change > objID.Date_of_Change
    

    【讨论】:

      【解决方案2】:

      架构

      因此,您有一个包含 版本化 对象的表,其中包含与该对象关联的更改记录以及一些详细信息和日期。

      现在你要选择

      • 每个对象的第一次更改
      • 最早的(在此对象更改的 GROUP 内)
      • DATE 列类型上使用MIN 函数

      这个最旧的应该被保留/保留并留下。应删除所有其他对象更改版本。

      解决

      A.分两步选择每个对象的第一个/最旧的更改。

      1. 选择每个对象的 MIN(日期):
      SELECT Object_ID, COUNT(Object_ID) AS Count_Changes, MIN(Date_of_Change) AS First_Change
      FROM table
      GROUP BY Object_ID
      

      结果集包含每个对象的 total 更改计数和第一次更改的日期。

      1. JOIN 中使用subquery 之前的结果选择第一个更改:
      SELECT *
      FROM table t
      -- join with a table-subquery having only 2 columns to correlate
      JOIN ( 
        SELECT Object_ID, MIN(Date_of_Change) AS First_Change
        FROM table
        WHERE Current_Step is NULL and Change = 'change'
        GROUP BY Object_ID
      ) m ON t.Object_ID = m.Object_ID AND t.Date_of_Change = m.First_Change
      WHERE Current_Step is NULL and Change = 'change'
      

      这是要保留而不是删除的行。每个对象的第一次更改应该保留而不是清理。

      B.现在我们可以反转 JOIN 条件来获取我们想要删除/清理的所有行:

      1. 更改日期比较

      ) m ON t.Object_ID = m.Object_ID AND t.Date_of_Change = m.First_Change

      不等于:

      ) m ON t.Object_ID = m.Object_ID AND t.Date_of_Change &lt;&gt; m.First_Change

      1. 首先运行干选,至少在删除之前获得计数。
      SELECT COUNT(Object_ID) AS records_to_remove
      FROM table t
      -- join with a table-subquery having only 2 columns to correlate
      JOIN ( 
        SELECT Object_ID, MIN(Date_of_Change) AS First_Change
        FROM table
        WHERE Current_Step is NULL and Change = 'change'
        GROUP BY Object_ID
      ) m ON t.Object_ID = m.Object_ID AND t.Date_of_Change <> m.First_Change
      WHERE Current_Step is NULL and Change = 'change'
      
      1. 使用 JOIN 准备 DELETE 语句(如果 DBMS 支持):
      DELETE FROM table t
      JOIN ( 
        SELECT Object_ID, MIN(Date_of_Change) AS First_Change
        FROM table
        WHERE Current_Step is NULL and Change = 'change'
        GROUP BY Object_ID
      ) m ON t.Object_ID = m.Object_ID AND t.Date_of_Change <> m.First_Change
      WHERE t.Current_Step is NULL AND t.Change = 'change'
      

      替代 JOIN 在其他 DBMS 上尝试 USING

      某些 DBMS 不支持在 DELETE 语句中加入 JOIN,但可以使用 USING 等替代方法:

      DELETE FROM table t
      USING ( 
        SELECT Object_ID, MIN(Date_of_Change) AS First_Change
        FROM table t2
        WHERE t2.Current_Step is NULL AND t2.Change = 'change'
      ) AS m
      WHERE ...
      AND t.Object_ID = m.Object_ID AND t.Date_of_Change <> m.First_Change
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-05
      • 1970-01-01
      • 2022-01-12
      • 2020-12-02
      • 2020-10-15
      • 2021-12-23
      • 1970-01-01
      相关资源
      最近更新 更多