【问题标题】:PostgreSQL Removing duplicatesPostgreSQL 删除重复项
【发布时间】:2017-02-17 03:06:38
【问题描述】:

我正在处理 postgres 查询以从表中删除重复项。下表是动态生成的,我想编写一个选择查询,如果第一行有重复值,它将删除记录。

表格看起来像这样

Ist col  2nd col
 4        62
 6        34
 5        26
 5        12

我想编写一个删除第 3 行或第 4 行的选择查询。

【问题讨论】:

标签: postgresql


【解决方案1】:
             select count(first) as cnt, first, second 
             from df1 
             group by first
             having(count(first) = 1)

如果你想保留其中的一行(抱歉,如果你想要的话,我最初错过了它):

             select first, min(second) 
             from df1 
             group by first

表名称为df1,列名称为firstsecond

如果你愿意,你实际上可以不用count(first) as cnt

冒着明显的风险,一旦您知道如何选择您想要(或不想要)的数据,那么删除记录的十几种方法中的任何一种都很简单。

如果你想更换表或创建一个新表,你可以使用create table as进行删除:

             create table tmp as 
             select count(first) as cnt, first, second 
             from df1 
             group by first
             having(count(first) = 1);

             drop table df1;

             create table df1 as select * from tmp;

或使用DELETE FROM:

DELETE FROM df1 WHERE first NOT IN (SELECT first FROM tmp);

您也可以使用select into等。

【讨论】:

  • @cricket_007 ??
  • 查看上面的评论“我怎样才能删除行?”。还有问题“从表中删除重复项”
  • @Hack-R 这不起作用,查询擦除了两行
【解决方案2】:

所以基本上我是这样做的

 create temp t1 as 
 select first, min (second) as second
 from df1 
 group by first

 select * from df1 
 inner join t1 on t1.first = df1.first and t1.second = df1.second

这是一个令人满意的答案。感谢您的帮助@Hack-R

【讨论】:

    【解决方案3】:

    不需要中间表:

    delete from df1
    where ctid not in (select min(ctid)
                       from df1
                       group by first_column);
    

    如果您要从大表中删除许多行,使用中间表的方法可能更快。


    如果您只想获取一列的唯一值,可以使用:

    select distinct on (first_column) *
    from the_table
    order by the_table;
    

    或者干脆

    select first_column, min(second_column)
    from the_table
    group by first_column;
    

    【讨论】:

    • @Uasthana:嗯,你说“从表中删除重复项”。
    • 这将删除第 1 行、第 2 行和第 4 行...我想他只是想删除第 4 行。
    • 不是having count(*) >= 1 吗?就像现在一样,它也会删除非重复记录(只有一个实例)。
    • 是的,应该是having count(*) >= 1@MarianoAnaya。更好的是完全删除having。我几乎删除了我需要的行。请删除having 子句@a_horse。
    【解决方案4】:
    • 如果您想SELECT 唯一行:

    SELECT * FROM ztable u
    WHERE NOT EXISTS (      -- There is no other record
        SELECT * FROM ztable x
        WHERE x.id = u.id   -- with the same id
        AND x.ctid < u.ctid -- , but with a different(lower) "internal" rowid
        );                  -- so u.* must be unique
    

    • 如果您想SELECT 上一个查询中被禁止的其他行:

    SELECT * FROM ztable nu
    WHERE EXISTS (           -- another record exists
        SELECT * FROM ztable x
        WHERE x.id = nu.id   -- with the same id
        AND x.ctid < nu.ctid -- , but with a different(lower) "internal" rowid
        );
    

    • 如果您想DELETE 记录,使表唯一(但每个 id 保留一条记录):

    DELETE FROM ztable d
    WHERE EXISTS (          -- another record exists
        SELECT * FROM ztable x
        WHERE x.id = d.id   -- with the same id
        AND x.ctid < d.ctid -- , but with a different(lower) "internal" rowid
        );
    

    【讨论】:

    • 只是出于好奇,如果需要根据更多条件保留行,而不仅仅是删除随机数(我相信 ctid 正在这样做),那么不应该使用 ctid被使用,对吗?我的意思是从长远来看它并不稳定。
    • ctid 用作最后的手段,如果没有其他列可用于区分删除或选择的各种候选者。 (其他 DBMS 有类似的伪列,但名称不同)在这种特殊情况下,可以使用 second_col,只保留最低(或最高)。
    • 我的回答没有问题。不过,可能你的问题(你提出的方式)有什么问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 2018-04-07
    • 2011-03-24
    • 2020-08-04
    相关资源
    最近更新 更多