表中有一个列,但无法从这部分查询中引用它

Che*_*ain 1 postgresql duplication subquery

我一直在学习Postgres(来自SQL Server),这个错误真的让我很困惑。

\n\n

这是带有一些示例数据的代码:

\n\n
create table T (\nID serial primary key,\nA varchar(1),\nB varchar(1),\nC varchar(1)\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x86\x91 测试表。

\n\n
insert into T (A, B, C)\nvalues('A', 'B', 'C'), ('A', 'B', 'C')\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x86\x91 插入重复项

\n\n
delete from T\nwhere ID in (\n    select t.ID\n    from (  select ID, row_number() over (partition by A,B,C order by A,B,C) as rn\n            from T) as t\n    where t.rn < (select max(t.rn) from t)\n    )\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x86\x91 删除重复项并保留最后一个条目。

\n\n

问题在于(select max(t.rn) from t)我假设这是一个菜鸟错误,与在引用带有别名的列时不知道 postgres 语法有关?

\n

Erw*_*ter 5

首先,partition by A,B,C order by A,B,C没有任何意义。由于您打算保留“最后”行(即具有最大的行ID),因此您可能的意思是:

partition by A,B,C order by ID
Run Code Online (Sandbox Code Playgroud)

尽管如此,语法还是无效的。此子查询表达式包含对外部查询的列的引用:(select max(t.rn) from t)。子查询的范围不包括外部查询中的列,因此rn在其中不可见。只有表的列t是。

您可以使用 CTE 来允许引用并使语法有效

WITH cte AS (SELECT id, row_number() OVER (PARTITION by a,b,c ORDER BY id) AS rn FROM t)
DELETE FROM t
WHERE  id IN (
    SELECT id
    FROM   cte
    WHERE  rn < (SELECT max(rn) FROM cte)
    )
Run Code Online (Sandbox Code Playgroud)

尽管如此,这个问题仍然是危险的废话。不要使用这个!
最大行数进行比较在逻辑上是无意义的,因为每组对等点可能有不同数量的重复项。会删除比应有的多得多的内容。

更简单、更正确:

DELETE FROM t
WHERE  id IN (
    SELECT t1.id
    FROM  (SELECT id, row_number() OVER (PARTITION by a,b,c ORDER BY id DESC) AS rn FROM t) t1
    WHERE  t1.rn > 1  --  all but the latest
    );
Run Code Online (Sandbox Code Playgroud)

反过来,可以更便宜地获得(假设所有列NOT NULL!):

DELETE FROM t
WHERE  EXISTS (
   SELECT FROM t AS t1
   WHERE t1.a = t.a
   AND   t1.b = t.b
   AND   t1.c = t.c
   AND   t1.id > t.id
   );
Run Code Online (Sandbox Code Playgroud)

“……存在具有更大 ID 的受骗者”

有关的: