我的查询删除整个表而不是重复的行。 视频为证: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);
您的查询将从每组重复数据中删除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
:
如果桌子没有钥匙,你就不能。
表具有唯一标识每一行的“键”。如果您的表没有任何键,那么您将无法从另一行中识别一行。
我能想到的删除重复行的唯一解决方法是:
例如:
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
)
现在你只有两行。