我的查询删除整个表而不是重复的行。 视频作为证明: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);
答案 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)
如果表没有键,则不能。
表具有用于唯一标识每一行的“键”。如果您的表没有任何键,那么您将无法识别另一行。
我能想到的唯一删除重复行的解决方法是:
例如:
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
)
现在您只有两行。