关于postgresql:Postgres 9.4.7 INSERT INTO没有ON CONFLICT

Postgres 9.4.7 INSERT INTO without ON CONFLICT

本问题已经有最佳答案,请猛点这里访问。

我真的想写一个这样的查询:

1
2
3
4
5
6
INSERT INTO test_table (id, dt, amt)
VALUES(4, CURRENT_TIMESTAMP, 15)
ON CONFLICT (id)
DO UPDATE
    SET dt = VALUES(dt)
        amt = VALUES(amt)

问题是,我使用的Postgres版本(9.4.7)不支持冲突上的构造。关于如何在不升级Postgres的情况下实现这一点有什么想法吗?


PostgreSQL 9.4没有任何内置的upsert(或merge)功能,并且在面对并发使用时高效地完成这项工作非常困难。

本文详细讨论了这个问题。

通常,您必须在两个选项之间进行选择:

  • 重试循环中的单个插入/更新操作;或
  • 锁定表并进行批合并

要获得完整的解决方案,请阅读此所以回答


如果你经常这样做。你可以写一个函数来为你做这件事。你可以通过两种方式来做到。

  • 先检查,然后插入或更新。
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
        CREATE OR REPLACE FUNCTION insert_test_table(INT, TIMESTAMP, VARCHAR)
        RETURNS INT AS
        $BODY$
        BEGIN
            IF (EXISTS(SELECT id FROM test_table WHERE id = $1)) THEN
                UPDATE test_table SET dt = $2, amt = $3 WHERE id = $1;
                RETURN 2;
            ELSE
                INSERT INTO test_table (id, dt, amt) VALUES($1, $2, $3);
                RETURN 1;
            END IF;
            RETURN 0;
            END;
        $BODY$
        LANGUAGE plpgsql;
  • 使用异常:
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        CREATE OR REPLACE FUNCTION insert_test_table(INT, TIMESTAMP, VARCHAR)
        RETURNS INT AS
        $BODY$
        BEGIN
            INSERT INTO test_table (id, dt, amt) VALUES($1, $2, $3);
            RETURN 1;
            EXCEPTION WHEN unique_violation THEN
                    BEGIN
                        UPDATE test_table SET dt = $2, amt = $3 WHERE id = $1;  
                        RETURN 2
                    END;
        END;
        $BODY$
        LANGUAGE plpgsql;

    第二种方法可能与其他独特的约束冲突,所以要小心。