无法使用 PostgreSQL 删除重复行

问题描述 投票:0回答:2

我的查询删除整个表而不是重复的行。 视频为证:https://streamable.com/3s843

create table customer_info (
    id INT,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    phone_number VARCHAR(50)
);
insert into customer_info (id, first_name, last_name, phone_number) values
(1, 'Kevin', 'Binley', '600-449-1059'),
(1, 'Kevin', 'Binley', '600-449-1059'),
(2, 'Skippy', 'Lam', '779-278-0889');

我的询问:

with t1 as (
select *, row_number() over(partition by id order by id) as rn
from customer_info)

delete
from customer_info 
where id in (select id from t1 where rn > 1);
sql postgresql duplicates sql-delete row-value-expression
2个回答
1
投票

您的查询将从每组重复数据中删除all行(所有行都共享您选择的相同

id
- 这就是wildplasser通过微妙的注释暗示的内容)。只有最初唯一的行才能幸存。因此,如果它“删除整个表”,则意味着根本没有唯一的行。

在您的查询中,欺骗是由

(id)
单独定义的,而不是如标题所示由 整行 定义的。

无论哪种方式,都有一个非常简单的解决方案:

DELETE FROM customer_info c
WHERE  EXISTS (
   SELECT FROM customer_info c1
   WHERE  ctid < c.ctid
   AND    c1 = c  -- comparing whole rows
   );

由于您处理完全相同的行,区分它们的剩余方法是内部元组 ID

ctid

小心表继承分区。那么可以涉及多个物理表,并且

ctid
在范围内不是唯一的。 (但是分区或继承子项中不应该有完全相同的行。)请参阅:

我的查询删除所有行,其中存在具有较小

ctid
的相同行。因此,只有每组受骗者中的“第一”行幸存下来。

值得注意的是,

NULL
值在这种情况下比较相等——这很可能是所期望的。 说明书:

SQL 规范要求逐行比较,如果满足则返回 NULL 结果取决于比较两个 NULL 值或一个 NULL 和一个 非空。 PostgreSQL 仅在比较两个结果时才这样做 行构造函数(如第 9.23.5 节)或比较行构造函数 到子查询的输出(如第 9.22 节)。在其他情况下 比较两个复合类型值时,两个 NULL 字段值 被认为是平等的,[...]

如果欺骗是由

id
单独定义的(如您的查询所示),那么这将起作用:

DELETE FROM customer_info c
WHERE  EXISTS (
   SELECT FROM customer_info c1
   WHERE  ctid < c.ctid
   AND    id = c.id
   );

但是,作为最后的手段,可能有比

ctid
更好的方法来决定保留哪些行!

显然,您可以添加一个

PRIMARY KEY
以避免最初的困境再次出现。对于第二种解释,
id
是候选者。

相关:

关于

ctid


0
投票

如果桌子没有钥匙,你就不能。

表具有唯一标识每一行的“键”。如果您的表没有任何键,那么您将无法从另一行中识别一行。

我能想到的删除重复行的唯一解决方法是:

  1. 在桌子上添加一把钥匙。
  2. 使用 键删除多余的行。

例如:

create sequence seq1;
alter table customer_info add column k1 int;
update customer_info set k1 = nextval('seq1');

delete from customer_info where k1 in (
  select k1 
  from (
    select
      k1,
      row_number() over(partition by id, first_name, last_name, phone_number) as rn
    from customer_info
  ) x
  where rn > 1
) 

现在你只有两行。

© www.soinside.com 2019 - 2024. All rights reserved.