无法使用PostgreSQL删除重复的行

时间:2019-08-18 21:41:40

标签: sql postgresql duplicates sql-delete row-value-expression

我的查询删除整个表而不是重复的行。 视频作为证明: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);

2 个答案:

答案 0 :(得分: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的相同行。因此,只有每组骗子的“第一”行都可以幸存。

值得注意的是, NULL值在这种情况下比较相等-很可能是所希望的。 The manual:

  

SQL规范要求按行比较以在以下情况下返回NULL   结果取决于比较两个NULL值或NULL和a   非NULL。 PostgreSQL仅在比较两个结果时才这样做   行构造函数(如第9.23.5节中所述)或比较行构造函数   到子查询的输出(如Section 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

答案 1 :(得分: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
) 

现在您只有两行。