是否可以使用“冲突”事件调用函数?

Edm*_*cho 0 postgresql

用于on conflict实现upsert行为是一个很棒的功能。我想知道是否要找到该功能的 RFC,是否可以找到一种使用on conflict事件来调用函数的方法,或者使用类似以下内容的方法:

on conflict
do $$
insert into another table
$$
Run Code Online (Sandbox Code Playgroud)

否则,考虑到我自己对 postgresql 还很陌生,有没有办法“捕获”冲突以进行进一步干预。

Che*_*ain 7

您不能使用该on conflict关键字影响其他表。正如官方文档所述,conflict_action 可能仅为以下之一:

conflict_action is one of:

    DO NOTHING
    DO UPDATE SET { column_name = { expression | DEFAULT } |
                    ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
                    ( column_name [, ...] ) = ( sub-SELECT )
                  } [, ...]
              [ WHERE condition ]
Run Code Online (Sandbox Code Playgroud)

但是,这并不意味着没有解决方法(至少对于该do nothing命令而言)。您可以使用一个函数与 PostgreSQL 中非常有用的关键字组合found来模拟类似的东西。

create or replace function generic_insert(
    p_user_name text
)
  returns boolean
  language plpgsql
as
$$
begin
    insert into users (user_name) values (p_user_name) on conflict do nothing;

    if not found then <your code> end if;

    return found;
end;
$$;
Run Code Online (Sandbox Code Playgroud)

这里的技巧是found关键字返回“受影响的行数”(最后执行的查询的行数)。由于do nothing没有影响任何行,found因此返回 false,因此您可以通过此知道您的插入导致命令do nothing的部分on conflict触发。当然,您可以在 if 语句中放入您想要的任何代码或插入命令。