比较 SQL 中的列时如何打破平局

How to break ties when comparing columns in SQL

我正在尝试删除 Postgres 中的重复项。我将其用作查询的基础:

DELETE FROM case_file as p
WHERE EXISTS (
    SELECT FROM case_file as p1
    WHERE p1.serial_no = p.serial_no
    AND p1.cfh_status_dt < p.cfh_status_dt
    );

它运行良好,除了当日期 cfh_status_dt 相等时,不会删除任何记录。

对于具有相同 serial_no 且日期相同的行,我想保留具有 registration_no 的行(如果有的话,此列也有 NULLS)。

有没有一种方法可以对所有一个查询执行此操作,可能使用 case 语句或其他简单比较?

DELETE FROM case_file AS p
WHERE  id NOT IN (
   SELECT DISTINCT ON (serial_no) id  -- id = PK
   FROM   case_file 
   ORDER  BY serial_no, cfh_status_dt DESC, registration_no
   );

这会保留每个 serial_no 的(一个)最新行,如果有多个候选者,则选择最小的 registration_no

NULL 按默认升序最后排序。因此,任何具有非空 registration_no 的行都是首选。

如果您想要 greatest registration_no,仍然对 NULL 值 last 进行排序,请使用:

   ...
   ORDER  BY serial_no, cfh_status_dt DESC, registration_no DESC NULLS LAST

参见:

  • Select first row in each GROUP BY group?
  • Sort by column ASC, but NULL values first?

如果您没有 PK (PRIMARY KEY) 或其他 UNIQUE NOT NULL(组合)列可用于此目的,您可以回退到 ctid。参见:

  • How do I (or can I) SELECT DISTINCT on multiple columns?

NOT IN 通常不是最有效的方法。但这处理涉及 NULL 值的重复项。参见:

  • How to delete duplicate rows without unique identifier

如果有很多重复项 - 你可以负担得起! - 创建一个新的、原始的 table 幸存者并替换旧的 table,而不是删除现有 table.[= 中的大部分行,效率会(高得多) 27=]

或者创建一个临时 table 幸存者,截断旧的并从临时 table 插入。通过这种方式,依赖对象(如视图或 FK 约束)可以保留在原地。参见:

  • How to delete duplicate entries?

幸存行只是:

SELECT DISTINCT ON (serial_no) *
FROM   case_file 
ORDER  BY serial_no, cfh_status_dt DESC, registration_no;