【问题标题】:Removing Duplicate Rows in PostgreSQL with multiple columns删除 PostgreSQL 中具有多列的重复行
【发布时间】:2018-08-19 10:58:11
【问题描述】:

我有一个包含以下列的“投票”表: voter, election_year, election_type, party 我需要删除 voterelection_year 组合的所有重复行,但我无法弄清楚如何执行此操作。

我运行了以下内容:

WITH CTE AS(
SELECT voter, 
       election_year,
       ROW_NUMBER()OVER(PARTITION BY voter, election_year ORDER BY voter) as RN

FROM votes
)
DELETE
FROM CTE where RN>1

基于另一个 StackOverflow 答案,但似乎这是特定于 SQL Server 的。我已经看到了使用唯一 ID 来做到这一点的方法,但是这个特殊的表没有那么奢侈。如何采用上述脚本来删除我需要的重复项?谢谢!

编辑:根据请求,使用一些示例数据创建表:

CREATE TABLE public.votes
(
    voter varchar(10),
    election_year smallint,
    election_type varchar(2),
    party varchar(3)
);

INSERT INTO votes
    (voter, election_year, election_type, party)
VALUES
    ('2435871347', 2018, 'PO', 'EV'),
    ('2435871347', 2018, 'RU', 'EV'),
    ('2435871347', 2018, 'GE', 'EV'),
    ('2435871347', 2016, 'PO', 'EV'),
    ('2435871347', 2016, 'GE', 'EV'),
    ('10215121/8', 2016, 'GE', 'ED')
;

【问题讨论】:

  • “基于另一个 StackOverflow 答案,但似乎这是特定于 SQL Server 的。”这个查询在我看来是完美的 PostgreSQL 语法。 PostgreSQL 还支持WITH .. AS(公用表表达式)和ROW_NUMBER() OVER (....) 就好了。“我怎样才能采用上面的脚本来删除我需要的重复项?谢谢!”没有表结构和示例数据很难说。检查stackoverflow.com/help/how-to-ask部分“帮助他人重现问题
  • 抱歉,给出的错误是“[42P01] 错误:关系“cte”不存在位置:157”

标签: sql postgresql


【解决方案1】:

这里有一个选项

DELETE FROM votes T1
    USING   votes T2
WHERE   T1.ctid < T2.ctid 
    AND T1.voter = T2.voter 
    AND T1.election_year  = T2.election_year;

http://sqlfiddle.com/#!15/4d45d/5

【讨论】:

    【解决方案2】:

    从 CTE 中删除或更新 CTE 在 Postgres 中不起作用,请参阅"PostgreSQL with-delete “relation does not exists”" 接受的答案。

    由于您没有主键,您可以(ab)使用ctid 伪列来标识要删除的行。

    WITH
    cte
    AS
    (
    SELECT ctid,
           row_number() OVER (PARTITION BY voter,
                                           election_year
                              ORDER BY voter) rn
           FROM votes
    )
    DELETE FROM votes
           USING cte
           WHERE cte.rn > 1
                 AND cte.ctid = votes.ctid;
    

    db<>fiddle

    并且可能考虑引入主键。

    【讨论】:

    • 我试过这个,但我得到 [42703] 错误:列 cte.ctid 不存在
    • @JGrindal:你确定你完全复制了声明?或者你刚刚编辑过你的?如果,您是否也将 ctid 添加到 CTE 中的 SELECT 中?
    • 是的,在我的 CTE 中忘记了 ctid。谢谢!
    • 加为 dbfiddle :D
    【解决方案3】:

    ctid 字段是存在于每个 PostgreSQL 表中的字段,对于表中的每条记录都是唯一的,表示元组的位置。 你做得几乎是对的,只需要 ctid 因为每一行都没有唯一的 id

    ;WITH CTE AS(
    SELECT ctid,voter, 
           election_year,
           ROW_NUMBER()OVER(PARTITION BY voter, election_year ORDER BY voter) as RN
    
    FROM votes
    )
    delete  FROM votes v where v.ctid in (select CTE.ctid from  CTE where CTE.RN>1)
    

    http://sqlfiddle.com/#!17/4d45d/14

    【讨论】:

      猜你喜欢
      • 2015-05-25
      • 1970-01-01
      • 1970-01-01
      • 2018-07-15
      • 2021-04-28
      • 1970-01-01
      • 2018-02-08
      • 2019-07-17
      • 1970-01-01
      相关资源
      最近更新 更多