我在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
行。
我该怎么办?
答案 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';
您可以参考以下示例:
注意:在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;
与你的功能相比,我改变了四件事:
returns integer
,以便能够返回insert
语句如果要区分来自调用者的更新或插入,可以将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
不会中止事务。