【问题标题】:Detect that an UPDATE has failed in PostgreSQL SQL-function (not PL/pgSQL)检测 PostgreSQL SQL 函数(不是 PL/pgSQL)中的 UPDATE 失败
【发布时间】:2010-10-31 08:25:31
【问题描述】:

为了模仿 MySQL-REPLACE 语句(又名 UPSERT),我需要尝试更新记录,如果失败 - 插入它。但是如何检测到我的 SQL 过程中的 UPDATE 失败了?

begin transaction;

create table pref_users (
       id varchar(32) primary key,
       first_name varchar(32),
       last_name varchar(32),
       female boolean,
       avatar varchar(128),
       city varchar(32),
       lat real check (-90 <= lat and lat <= 90),
       lng real check (-90 <= lng and lng <= 90),
       last_login timestamp default current_timestamp,
       last_ip inet,
       medals smallint check (medals > 0)
);
create table pref_rate (
       obj varchar(32) references pref_users(id),
       subj varchar(32) references pref_users(id),
       good boolean,
       fair boolean,
       nice boolean,
       about varchar(256),
       last_rated timestamp default current_timestamp
);

create table pref_money (
       id varchar(32) references pref_users,
       yw char(7) default to_char(current_timestamp, 'YYYY-WW'),
       money real
);
create index pref_money_yw_index on pref_money(yw);

create or replace function update_pref_users(id varchar,
       first_name varchar, last_name varchar, female boolean,
       avatar varchar, city varchar, last_ip inet) returns void as $$

       update pref_users set
            first_name = $2,
            last_name = $3,
            female = $4,
            avatar = $5,
            city = $6,
            last_ip = $7
        where id = $1;

        -- XXX how to detect failure here? XXX

       insert into pref_users(id, first_name, last_name,
            female, avatar, city, last_ip)
            values ($1, $2, $3, $4, $5, $6, $7);
$$ language sql;

commit;

我是否需要在 update_pref_users SQL 函数中使用第二对 BEGIN/COMMIT?

【问题讨论】:

  • 我不确定我是否理解正确。 Plpgsql 函数本质上是原子的。如果某些事情失败了,它将被回滚。

标签: sql postgresql stored-procedures


【解决方案1】:

您不能将 SQL 用作一门语言,您需要 pl/pgsql,因为 SQL 中缺少 if-else 结构。

在 pl/pgsql 中,您可以使用特殊变量 FOUND 来查看查询是否找到了某些内容。

UPDATE ...;
IF NOT FOUND THEN -- UPDATE didn't touch anything
  INSERT ...;
END IF;

不需要额外的 SELECT 语句。

【讨论】:

  • 感谢您的回答。我想知道它是否是“原子的”,即它不能发生,发现不是真的,但是另一个会话在两者之间调用一个 INSERT?
【解决方案2】:
IF EXISTS(<query to select record required for update>)
    UPDATE ...
ELSE
    INSERT ...

【讨论】:

  • 谢谢,但不是 plpgsql 吗?我正在尝试找到一个 SQL 解决方案。如果中间有 INSERT,您的建议是原子的还是会失败?
  • 不需要SELECT查询,直接用FOUND看看UPDATE有没有碰到什么。
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-15
  • 2018-12-06
相关资源
最近更新 更多