Postgresql函数:获取更新或插入行的id

时间:2015-05-14 09:14:06

标签: postgresql function

我在postgresql数据库中有这个功能,如果存在则更新行或如​​果不存在则插入新行:

CREATE OR REPLACE FUNCTION insert_or_update(val1 integer, val2 integer) RETURNS VOID AS $$ 
DECLARE 
BEGIN 
    UPDATE my_table SET col2 = val2 WHERE col1 = val1; 
    IF NOT FOUND THEN 
    INSERT INTO my_table (col2) values ( val2 ); 
    END IF; 
END; 
$$ LANGUAGE 'plpgsql';

目前它工作正常,但如果更新或插入,我希望得到id行。
我该怎么办?

3 个答案:

答案 0 :(得分:1)

您可以使用CURVAL(SEQUENCE_NAME_OF_TABLE)方法获取LastInsert ID。

但最好的方法是使用带有RETURNING子句的INSERT或UPDATE查询。

    CREATE OR REPLACE FUNCTION insert_or_update(val1 integer, val2 integer) RETURNS VOID AS $$ 
    DECLARE 
    BEGIN 
        UPDATE my_table SET col2 = val2 WHERE col1 = val1 RETURNING col1; 
        IF NOT FOUND THEN 
        INSERT INTO my_table (col2) values ( val2 ) RETURNING col1; 
        END IF; 
    END; 
    $$ LANGUAGE 'plpgsql';

您可以参考以下示例:

  1. Insert Command - Last Example
  2. Postgres with RETURNING clause
  3. 注意:在UPDATE查询中,您的WHERE子句为col1=val1。我假设Val1将是唯一值,否则将更新多个记录。希望你知道。我认为col1是你的主键,就像ID一样。

答案 1 :(得分:1)

您的功能被声明为returns void,因此无法返回任何内容。

假设col1是主键并且也定义为序列号,您可以执行以下操作:

CREATE OR REPLACE FUNCTION insert_or_update(val1 integer, val2 integer) 
    RETURNS int 
AS $$ 
DECLARE 
  l_id integer;
BEGIN 
    l_id := val1; -- initialize the local variable.

    UPDATE my_table 
       SET col2 = val2 
    WHERE col1 = val1; -- !! IMPORTANT: this assumes col1 is unique !!

    IF NOT FOUND THEN 
       INSERT INTO my_table (col2) values ( val2 ) 
       RETURNING col1 -- this makes the generated value available
       into l_id;     -- and this stores it in the local variable
    END IF; 

    return l_id; -- return whichever was used.
END; 
$$ LANGUAGE plpgsql;

与你的功能相比,我改变了四件事:

  1. 该函数声明为returns integer,以便能够返回
  2. 您需要一个变量,您可以在其中存储insert语句
  3. 中返回的值
  4. 最后需要返回生成的值:
  5. 语言名称是标识符,因此不能使用单引号引用。
  6. 如果要区分来自调用者的更新或插入,可以将l_id初始化为null。在这种情况下,如果发生更新,函数将返回null,否则返回一些值。

答案 2 :(得分:0)

PostgreSQL wiki's entry on UPSERT表示将INSERT ... ON CONFLICT UPDATE添加到PostgreSQL 9.5中。这将允许您更直接地表达您想要的操作,而无需借助存储过程和/或引入竞争条件。

在早期的PostgreSQL版本中表达此操作非常棘手,没有数据库损坏和/或竞争条件的风险。到目前为止发布的代码片段都包含一个错误,如果两个调用者碰巧想要插入相同的不存在的行,则初始UPDATE将更新零行,然后他们将尝试INSERT,一个其中将失败。它至少应该是安全的,中止查询和正在进行的任何事务。

PostgreSQL documentation on INSERT(在该页面上搜索文本"尝试插入新库存项目以及库存数量")显示如何在PostgreSQL 9.4上安全正确地执行此操作早。特别值得注意的是,它首先尝试INSERT 以避免在该前端进行任何比赛,如果失败,则现在知道的行的UPDATE是否存在。它使用SAVEPOINT来确保失败的INSERT不会中止事务。