IF UPDATE RETURNS没有行更新INSERT数据

时间:2017-05-22 19:50:22

标签: sql postgresql postgresql-9.6

我想UPDATE记录是否存在,否则在我的Java项目的一个查询中将值INSERT到表中。

DO
$do$
BEGIN
IF EXISTS
(SELECT 1 NOTES WHERE USER_ID = '2' AND EVENT_ID ='4') THEN 
UPDATE NOTES SET NOTES='MY notes' WHERE USER_ID = '2' AND EVENT_ID ='4' 
ELSE 
INSERT INTO NOTES VALUES
((SELECT max(NOTES_ID)+1 FROM NOTES), '4, 2','1',''); END IF; END 
$do$ 

这是我迄今为止所拥有的,但是自从Postgres 9.5以来,必须有一些变化,我得到了:

ERROR:  syntax error at or near "ELSE"
LINE 7: ELSE 

2 个答案:

答案 0 :(得分:0)

有很多方法可以实现这一目标。您可以使用新的UPSERT语法EXISTS(只修复Clodoaldo提到的分号)或使用FOUND变量:

DO $do$
BEGIN
     UPDATE NOTES SET NOTES='MY notes' WHERE USER_ID = '2' AND EVENT_ID ='4';
     IF NOT FOUND THEN
          INSERT INTO NOTES VALUES ((SELECT max(NOTES_ID)+1 FROM NOTES), '4, 2','1','');
     END IF;
END $do$;

但要注意racing conditions

答案 1 :(得分:0)

不需要PL / pgSQL块。

这可以使用可写CTE的单个SQL语句来完成:

with updated as (
  UPDATE NOTES 
    SET NOTES='MY notes' 
  WHERE USER_ID = 2 
    AND EVENT_ID = 4
  returning *
)
INSERT INTO NOTES (notes_id, event_id, user_id, notes)
select (SELECT max(NOTES_ID)+1 FROM NOTES), --<< Do NOT do this!!
       4,
       2, 
       'My notes'
where not exists (select * from updated);

请注意,使用max(notes_id) + 1生成“唯一”ID对于并发使用并不安全,如果表大小增加,则无法很好地扩展。

另外:你应该使用数字文字来表示数字,而不是字符串。 2是一个数字'2'是一个字符串。

如果您在(user_id, event_id)上有一个唯一索引(您应该了解问题的性质),您还可以使用Postgres 9.5中引入的insert on conflict

INSERT INTO NOTES (notes_id, event_id, user_id, notes)
VALUES (
    (SELECT max(NOTES_ID)+1 FROM NOTES), --<< Do NOT do this!
    4, 2, 'My notes')
ON CONFLICT (user_id, event_id) 
  DO UPDATE set notes = excluded.notes;

警告:

如果您想以可靠,并发安全且可扩展的方式生成唯一ID,拥有来使用序列。 NOT 使用反模式max() + 1