Postgres - 删除重复行以确保唯一索引有效

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

我的表格结构如下:

id | foodid | ingredientid

我想创建一个唯一索引,如下所示:

create unique index foodingredient_foodid_ingredientid_uindex
    on foodingredient (foodid, ingredientid);

问题是该表包含大量重复的 foodid 和做什么成分。这些是不必要的,我想删除它们。

如果我跑步:

select count(*)
from foodingredient
group by foodid, ingredientid
having count(*) > 1
order by count desc

这将返回 50 万行。因此,手动修复这些问题不是一个选择。

所以我想做的是删除所有重复项,同时保留原始内容。

id | foodid | ingredientid
1  | 144    | 531
2  | 144    | 531
3  | 144    | 531
4  | 144    | 531

变成:

id | foodid | ingredientid
1  | 144    | 531

有没有办法通过查询来做到这一点?

sql postgresql duplicates postgresql-9.5
3个回答
3
投票

你可以用存在来做到这一点:

delete from foodingredient t
where exists (
  select 1 from foodingredient
  where foodid = t.foodid and ingredientid = t.ingredientid and id < t.id
)

查看演示


1
投票
DELETE FROM foodingredient a
USING foodingredient b
WHERE a.id > b.id
    AND a.foodid = b.foodid 
    AND a.ingredientid = b.ingredientid;

0
投票

您也可以仅选择不同的行并使用它们来创建新表。

简单选择只是为了看看发生了什么。

SELECT DISTINCT ON (foodid, ingredientid) id, foodid, ingredientid
   FROM foodingredient LIMIT 100

从上面的 SELECT 创建新表。

CREATE TABLE foodingredient_uniq AS select * FROM (
  SELECT DISTINCT ON(foodid, ingredientid) id, foodid, ingredientid
  FROM foodingredient
)

如果您想按 id 排序新表,那么还要添加 ORDER BY

CREATE TABLE foodingredient_uniq AS select * FROM (
  SELECT DISTINCT ON(foodid, ingredientid) id, foodid, ingredientid
  FROM foodingredient
) t1 ORDER BY t1.id

然后删除旧表并将 foodingredient_uniq 重命名为 foodingredient。对于非常大的表,它比上面的自连接解决方案要快得多。在我自己的用例中,24 小时 vs 20 分钟,具有 200M 行表和约 30% 的唯一行。

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