Postgresql使用CTE删除行删除所有行

Postgresql Using CTE to delete rows removes all rows

我有以下 table:

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 删除了每一行,但子查询按预期工作?

向 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 运算符需要具有单列的 table。您的子查询仅包含一列,因此名称无关紧要(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 子句视为不存在并继续删除所有内容,这是我没有预料到的行为。