【问题标题】:Postgresql Using CTE to delete rows removes all rowsPostgresql 使用 CTE 删除行删除所有行
【发布时间】:2020-10-21 00:13:05
【问题描述】:

我有下表:

DROP TABLE IF EXISTS test;
CREATE TABLE test (
  id SERIAL,
  username varchar(32)
);
INSERT INTO test (username)
VALUES ('Jesse'), ('Jesse'), ('Scott'), ('Scott'), ('John');

当有重复行时,我想删除最低的 ID。我进行了以下查询以查找目标行:

SELECT MIN(id), username
FROM test
GROUP BY username
HAVING count(*) > 1;

当我尝试在 CTE 中使用它时,它最终会删除每一行:

WITH to_delete AS (
  SELECT MIN(id), username
  FROM test
  GROUP BY username
  HAVING count(*) > 1
)
DELETE FROM test
WHERE id IN (
  SELECT id
  FROM to_delete
);


但是,当我运行相同的查询并将 CTE 作为子查询时,它按预期工作:

DELETE FROM test
WHERE id IN (
  SELECT MIN(id)
  FROM test
  GROUP BY username
  HAVING count(*) > 1
);

我确信这背后有一些逻辑,但我在搜索中没有找到源代码。为什么 CTE 删除每一行,但子查询按预期工作?

【问题讨论】:

    标签: postgresql subquery common-table-expression sql-delete


    【解决方案1】:

    向您的 CTE 添加列别名可使 DELETE 按预期工作。

    with
    
      to_delete as (
        select
          min(id) as id,
          username
        from
          test
        group by
          username
        having
          count(*) > 1
      )
    
    delete from
      test
    where
      id in (
        select
          id
        from
          to_delete
      )
    ;
    
    table test;
    
     id │ username
    ════╪══════════
      7 │ Jesse
      9 │ Scott
     10 │ John
    (3 rows)
    

    IN 运算符需要一个包含单列的表。您的子查询仅包含一列,因此名称无关紧要(postgres 将为该列分配函数的名称,因此min 而不是id)。您的 CTE 包含两列,因此您编写了一个选择其中之一的子查询,但它没有正确别名为 id

    with
    
      to_delete as (
        select
          min(id) as id,
          username
        from
          test
        group by
          username
        having
          count(*) > 1
      )
    
    select id from to_delete;
    
    

    导致错误

    ERROR:  42703: column "id" does not exist
    LINE 15: select id from  to_delete;
    

    有趣的是,DELETE 语句没有出错,而是将 WHERE 子句视为不存在并继续删除所有内容,这是我没想到的行为。

    【讨论】:

    • 呸,你是对的!我在测试时只做了SELECT *。如果我搞砸了这么简单的事情,我预计会出错,我想知道这是否是一个错误
    • 这不是错误,这是预期行为。这是因为它使用了“相关子查询”,您可以在这里找到更多信息:wiki.postgresql.org/wiki/…
    猜你喜欢
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    • 2016-06-12
    相关资源
    最近更新 更多