PostgreSQL upsert功能(insert on conflict do)的用法

转载:PostgreSQL upsert功能(insert on conflict do)的用法

1. 背景

PostgreSQL 9.5 引入了一项新功能,UPSERT(insert on conflict do),当插入遇到约束错误时,直接返回,或者改为执行UPDATE。

语法如下:

Command:     INSERT  
Description: create new rows in a table  
Syntax:  
[ WITH [ RECURSIVE ] with_query [, ...] ]  
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]  
    { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }  
    [ ON CONFLICT [ conflict_target ] conflict_action ]  
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]  
  
where conflict_target can be one of:  
  
    ( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]  
    ON CONSTRAINT constraint_name  
  
and conflict_action is one of:  
  
    DO NOTHING  
    DO UPDATE SET { column_name = { expression | DEFAULT } |  
                    ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) |  
                    ( column_name [, ...] ) = ( sub-SELECT )  
                  } [, ...]  
              [ WHERE condition ]  

PostgreSQL 9.5以前的版本,可以通过函数,或者with语法来实现UPSERT类似的功能。

2. 9.5+ UPSERT用法举例

创建一张测试表,其中一个字段为唯一键或者主键。

  1. 不存在则插入,存在则更新。

  2. 不存在则插入,存在则直接返回(不做任何处理)

9.5 UPSERT用法举例

用户可以根据实际需求,使用不同的方法。

  1. 函数

  2. WITH语法,用法1

    存在则更新,不存在则插入。

    替换变量,进行测试。

    同时插入一条不存在的值,只有一个会话成功,另一个会话会报PK约束错误。

  3. WITH语法,用法2

    即使表没有PK或者唯一约束,也能保证并发。

    3.1 对于记录不存在,可以保证只有一个session插入数据,对于同一条数据更新,先来的session会lock着记录,后来的session会wait。

    替换变量,进行测试。

    3.2 对于记录不存在,可以保证只有一个session插入数据,对于同一条数据更新,先来的session会更新数据,后来的session不等待,直接失败。

    替换变量,进行测试。

最后更新于

这有帮助吗?