You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL不创建新表删除重复行:存储过程异常排查

解决PostgreSQL删除表内重复行的问题

先说说你写的存储过程为啥不行:

  • SELECT * INTO _temp_table 逻辑错误:你定义的_temp_table是字符串变量,但SELECT INTO是把查询结果赋值给变量,不是创建表。这行要么会因为查询返回多行报错,要么根本没创建出临时表,后续操作自然全部失效。
  • 就算改成正确的临时表创建方式,先删全表再插入的方式风险极高——如果执行中途出问题,原表数据会丢失,而且锁表时间长,影响其他业务操作。

下面给两种不用临时表、直接删除重复行的方法,根据你的表结构选择:

方法1:表有主键/唯一标识列(比如自增id)

如果表A有主键(比如id),用窗口函数标记重复行,只保留每组内的一行,删掉多余重复项:

WITH duplicates AS (
    SELECT id,
           ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY id) AS rn
    FROM A
)
DELETE FROM A
USING duplicates
WHERE A.id = duplicates.id AND duplicates.rn > 1;

PARTITION BY col1, col2按重复列分组,ORDER BY id保留每组里id最小的行,rn>1的就是需要删除的重复行。

方法2:表只有col1和col2两列(无主键)

PostgreSQL中每个行都有唯一的ctid可以用来区分不同行,用它来标记重复行:

WITH duplicates AS (
    SELECT ctid,
           ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY ctid) AS rn
    FROM A
)
DELETE FROM A
USING duplicates
WHERE A.ctid = duplicates.ctid AND duplicates.rn > 1;

逻辑和方法1一致,只是用ctid代替主键来识别不同行。

如果你非要修改原来的存储过程(不推荐),正确的临时表写法如下,但依然不如上面的方法安全高效:

CREATE PROCEDURE test_procedure()
LANGUAGE plpgsql
AS $$
BEGIN
    -- 正确创建临时表
    CREATE TEMP TABLE TempTable AS 
    SELECT * FROM A GROUP BY col1, col2;
    
    -- 开启事务避免数据丢失(原代码无事务,风险极大)
    BEGIN
        DELETE FROM A;
        INSERT INTO A SELECT * FROM TempTable;
        COMMIT;
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            RAISE;
    END;
    
    DROP TABLE TempTable;
END; $$

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 07:05:49