首页 > 数据库 > SQL覆盖写入 INSERT ON CONFLICT

SQL覆盖写入 INSERT ON CONFLICT

时间:2023-03-08 22:22:21浏览次数:33  
标签:INSERT DO t1 excluded SQL 主键 CONFLICT

SQL覆盖写入 INSERT ON CONFLICT

ON CONFLICT DO UPDATE SET column_name = { expression | DEFAULT }

ON CONFLICT DO UPDATE NOTHING

[ 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 ] [, ...] ]
其中,conflict_target为:
    ( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] )
其中,conflict_action为:
    DO NOTHING
    DO UPDATE SET { column_name = { expression | DEFAULT } |
                    ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] )
                  } [, ...]
              [ WHERE condition ] 

ON CONFLICT子句可以实现覆盖写入。该子句由conflict_target和conflict_action组成。

参数 说明
conflict_target conflict_action取值为Do Update时,conflict_target需要指定用来定义冲突的主键列或唯一索引列。conflick_action取值为Do Nothing时,conflict_target可省略。
conflict_action 用于指定冲突后需要执行的动作。取值说明:DO NOTHING:如果conflict_target指定的列有冲突,则丢弃待插入的数据。DO UPDATE:如果conflict_target指定的列有冲突,则按照后面的UPDATE子句进行数据覆盖。

示例

创建一个表t1,表中拥有4列,其中a列为主键,建表语句如下:

CREATE TABLE t1 (a int PRIMARY KEY, b int, c int, d int DEFAULT 0);

对表t1插入一行数据,主键列a的值为0,插入数据语句如下:

INSERT INTO t1 VALUES (0,0,0,0);

查看表数据:

SELECT * FROM t1;

返回信息如下:

 a | b | c | d
---+---+---+---
 0 | 0 | 0 | 0
(1 row)

如果再对表t1插入一行数据,主键列a的值还是0,则会返回一个报错,插入数据语句如下:

INSERT INTO t1 VALUES (0,1,1,1);

报错信息如下:

ERROR:  duplicate key value violates unique constraint "t1_pkey"
DETAIL:  Key (a)=(0) already exists.

如果不希望出现上述报错信息,可以使用本文介绍的覆盖写入特性来进行处理:

  • 使用ON CONFLICT DO NOTHING子句:主键冲突的情况下,不执行任何操作(适用于有冲突丢弃冲突数据的场景)。

    插入数据语句如下:

    INSERT INTO t1 VALUES (0,1,1,1) ON CONFLICT DO NOTHING;
    

    查看表数据:

    SELECT * FROM t1;
    

    表t1没有进行任何操作,返回示例如下:

     a | b | c | d
    ---+---+---+---
     0 | 0 | 0 | 0
    (1 row)
    
  • 使用ON CONFLICT DO UPDATE子句:主键冲突的情况下,更新非主键的列(适用于全部列覆盖写入的场景)。

    插入数据语句如下:

    INSERT INTO t1 VALUES (0,2,2,2) ON CONFLICT (a) DO UPDATE SET (b, c, d) = (excluded.b, excluded.c, excluded.d);
    

    INSERT INTO t1 VALUES (0,2,2,2) ON CONFLICT (a) DO UPDATE SET b = excluded.b, c = excluded.c, d = excluded.d; 
    

    在DO UPDATE SET子句中,可以使用excluded表示冲突的数据构成的伪表,在主键冲突的情况下,引用伪表中列的值覆盖原来列的值。上述语句中,新插入的数据(0,2,2,2)构成了一个伪表,伪表包含1行4列数据,表名为excluded,可以使用excluded.b, excluded.c, excluded.d去引用伪表中的列。

    查看表数据:

    SELECT * FROM t1;
    

    表t1中的非主键列进行了更新,返回示例如下:

     a | b | c | d
    ---+---+---+---
     0 | 2 | 2 | 2
    (1 row)
    

除了上述两种情况,覆盖写入功能支持更多使用场景,场景如下:

  • 主键冲突的情况下,在部分列中覆盖写入数据(适用于基于冲突数据覆盖部分列的场景):

    例如主键冲突后,仅覆盖c列的数据,插入数据语句如下:

    INSERT INTO t1 VALUES (0,0,3,0) ON CONFLICT (a) DO UPDATE SET c = excluded.c;
    

    查看表数据:

    SELECT * FROM t1;
    

    返回示例如下:

     a | b | c | d
    ---+---+---+---
     0 | 2 | 3 | 2
    (1 row)
    
  • 主键冲突的情况下,更新部分列的数据(适用于基于原始数据更新部分列场景):

    例如主键冲突后,将d列的数据加1,插入数据语句如下:

    INSERT INTO t1 VALUES (0,0,3,0) ON CONFLICT (a) DO UPDATE SET d = t1.d + 1;
    

    查看表数据:

    SELECT * FROM t1;
    

    返回示例如下:

     a | b | c | d
    ---+---+---+---
     0 | 2 | 3 | 3
    (1 row)
    
  • 主键冲突的情况下,更新数据为默认值(适用于冲突后,回退数据到默认值的场景):

    例如主键冲突后,将d列恢复到默认值(上文中d列的默认值为0),插入数据语句如下:

    INSERT INTO t1 VALUES (0,0,3,0) ON CONFLICT (a) DO UPDATE SET d = default;
    

    查看表数据:

    SELECT * FROM t1;
    

    返回示例如下:

     a | b | c | d
    ---+---+---+---
     0 | 2 | 3 | 0
    (1 row)
    
  • 插入多条数据:

    • 例如插入2行数据,其中主键冲突的行不进行任何操作,主键不冲突的行正常插入,插入数据语句如下:

      INSERT INTO t1 VALUES (0,0,0,0), (1,1,1,1) ON CONFLICT DO NOTHING;
      

      查看表数据:

      SELECT * FROM t1;
      

      返回示例如下:

       a | b | c | d
      ---+---+---+---
       0 | 2 | 3 | 0
       1 | 1 | 1 | 1
      (2 rows)
      
    • 例如插入2行数据,主键冲突的行进行覆盖写入,主键不冲突的行正常插入,插入数据语句如下:

      INSERT INTO t1 VALUES (0,0,0,0), (2,2,2,2) ON CONFLICT (a) DO UPDATE SET (b, c, d) = (excluded.b, excluded.c, excluded.d);
      

      查看表数据:

      SELECT * FROM t1;
      

      返回示例如下:

       a | b | c | d
      ---+---+---+---
       0 | 0 | 0 | 0
       1 | 1 | 1 | 1
       2 | 2 | 2 | 2
      (3 rows)
      
  • 插入的数据来自于子查询,如果主键冲突,则覆盖写入(用于合并两表数据或更复杂的INSERT INTO SELECT场景):

    创建表t2,数据结构与表t1一致,建表语句如下:

    CREATE TABLE t2 (like t1);
    

    在表t2中插入两行数据,插入数据语句如下:

    INSERT INTO t2 VALUES (2,22,22,22),(3,33,33,33);
    

    将表t2的数据插入表t1,如果主键冲突,则覆盖写入非主键的列,插入数据语句如下:

    INSERT INTO t1 SELECT * FROM t2 ON CONFLICT (a) DO UPDATE SET (b, c, d) = (excluded.b, excluded.c, excluded.d);
    

    查看表数据:

    SELECT * FROM t1;
    

    返回示例如下:

     a | b  | c  | d
    ---+----+----+----
     0 |  0 |  0 |  0
     1 |  1 |  1 |  1
     2 | 22 | 22 | 22
     3 | 33 | 33 | 33
    (4 rows)
    

标签:INSERT,DO,t1,excluded,SQL,主键,CONFLICT
From: https://www.cnblogs.com/liurui12138/p/17196493.html

相关文章

  • 【MySQL】多表的查询
    为什么需要多表查询1、单表查询在WEB要经过几次http交互,再不同表之间才能查找到数据。会浪费很多时间,因此需要多表查询。2、如果多张表合在一张表中,会导致会多字段不......
  • sql
    SQL基础条件查询语法格式:select字段1,字段2...from表名where条件;执行顺序:先from,然后where,最后select.<,>,<=,>=,<>,!=,and,between…and….,isnull,isnotn......
  • SQL优化
    插入数据如果我们需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化。insertintotb_testvalues(1,'tom');insertintotb_testvalues(2,'cat');insert......
  • 【Mybatis】【SQL执行过程】【三】Mybatis源码解析-SqlSession、Executor的创建
    1 前言上节我们看到 MapperMethod执行的前奏,看到其实都是调用的SqlSession去执行的,而SqlSession又是调用其内部的Executor来进行执行的,那么这节我们先来看下回......
  • 66.mysql的json语法
    Mysql的json语法:#创建json表createtablet_json(idintprimarykey,snamevarchar(20),infojson);#插入json数据insertintot_json(id,sname,info)values(1,'......
  • 【MySQL】排序和分页
    排序ORDERBY多列;#强调格式:WHERE需要声明在FROM后,ORDERBY之前。先排序Country 再排序CustomerName,默认是按ASC排序的。SELECT*FROMCustomersORDERBYCountr......
  • 2.安装mysql教程
    day1MySQL1.安装MySQLMySQL,本质上就是一个软件。推荐用5.7.31版本。1.1下载,安装5.7.31比较稳定https://downloads.mysql.com/archives/community/1.2配置mysql安......
  • 【SQL】 逻辑运算符与位运算符
    逻辑运算符   ......
  • MySQL查看数据库性能常用命令和实战教学
    MySQL查看数据库性能常用命令#列出MySQL服务器运行各种状态值showglobalstatus;#查询MySQL服务器配置信息语句showvariables;#慢查询showvariableslike'%sl......
  • sqlalchemy 基础查询操作
    in查询db.query(UserAccount#模型名称).filter(account_type.in_(['1','2','3'])).all()array_agg聚合查询db.query(func.min(UserAccount.username)#去重,......