
# INSERT
#### 功能描述
向表中插入一行或多行数据。
#### 注意事项
- 只有拥有表INSERT权限的用户，才可以向表中插入数据。用户被授予insert any table权限，相当于用户对除系统模式之外的任何模式具有USAGE权限，并且拥有这些模式下表的INSERT权限。
- 如果使用RETURNING子句，用户必须要有该表的SELECT权限。
- 如果使用ON DUPLICATE KEY UPDATE，用户必须要有该表的INSERT、UPDATE权限，UPDATE子句中列的SELECT权限。
- 如果使用query子句插入来自查询里的数据行，用户还需要拥有在查询里使用的表的SELECT权限。
- 生成列不能被直接写入。在INSERT命令中不能为生成列指定值，但是可以指定关键字DEFAULT。
 
#### 语法格式
```
INSERT [/*+ plan_hint */] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
    [(col_name [, col_name] ...)]
    {VALUES | VALUE} (value_list) [, (value_list)] ...
    [ON DUPLICATE KEY UPDATE column_name = {expression | DEFAULT}[, ...]]
    [ RETURNING {* | {output_expression [ [ AS ] output_name ] }[, ...]} ];
INSERT [/*+ plan_hint */] [IGNORE] [INTO] tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    SET column_name = {expression | DEFAULT}[, ...]
    [ON DUPLICATE KEY UPDATE column_name = {expression | DEFAULT}[, ...]]
    [ RETURNING {* | {output_expression [ [ AS ] output_name ] }[, ...]} ];
INSERT [/*+ plan_hint */] [IGNORE] [INTO] tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    [(col_name [, col_name] ...)]
    query
    [ON DUPLICATE KEY UPDATE column_name = {expression | DEFAULT}[, ...]]
    [ RETURNING {* | {output_expression [ [ AS ] output_name ] }[, ...]} ]; 
INSERT [/*+ plan_hint */] [IGNORE] [INTO] view_name
    [(col_name [, col_name] ...)]
    {VALUES | VALUE} (value_list) [, (value_list), ...]
    [ RETURNING {* | {output_expression [ [ AS ] output_name ] }[, ...]} ];
INSERT [/*+ plan_hint */] [IGNORE] [INTO] view_name
    SET column_name = {expression | DEFAULT}[, ...]
    [ RETURNING {* | {output_expression [ [ AS ] output_name ] }[, ...]} ];
INSERT [/*+ plan_hint */] [IGNORE] [INTO] view_name
    [(col_name [, col_name] ...)]
    query
    [ RETURNING {* | {output_expression [ [ AS ] output_name ] }[, ...]} ];
```
#### 参数说明
- **plan_hint子句**
  以/\*+ \*/的形式在INSERT关键字后，用于对INSERT对应的语句块生成的计划进行hint调优。每条语句中只有第一个/\*+ plan_hint \*/注释块会作为hint生效，里面可以写多条hint。
  
- **IGNORE**
  INSERT语句使用IGNORE关键字时，可将部分ERROR级别的错误降级为WARNING级别，并根据不同的错误场景将无效值调整为最接近的值。GaussDB支持错误降级的场景如下：
  - 破坏NOT NULL约束。
  
  - 唯一键冲突。
  
  - 插入的值无法匹配对应的分区。
  
  - 指定分区插入时，插入的数据与指定分区不匹配。
  
  - 子查询返回多行。
  
  - sql_mode为宽松模式的场景。
   
- **table_name**
  要插入数据的目标表名。
  取值范围：已存在的表名。
  
- **partition_name**
  分区名。
  
- **column_name**
  目标表中的字段名称：
  - 字段名可以有子字段名或者数组下标修饰。
  
  - 没有在字段列表中出现的每个字段，将由系统默认值，或者声明时的默认值填充，若都没有则用NULL填充。例如，向一个复合类型中的某些字段插入数据的话，其他字段将是NULL。
  
  - 目标字段（column_name）可以按顺序排列。如果没有列出任何字段，则默认全部字段，且顺序为表声明时的顺序。
  
  - 如果value子句和query中只提供了N个字段，则目标字段为前N个字段。
  
  - value子句和query提供的值在表中从左到右关联到对应列。
  
  
  取值范围：已存在的字段名。
  
- **expression**
  赋予对应column的一个有效表达式或值：
  - 如果是在INSERT ON DUPLICATE KEY UPDATE语句下，expression可以为VALUES(column_name)，用来表示引用冲突行对应的column_name字段的值。其中VALUES(column_name)支持嵌套在复合表达式中，例如：VALUES(column_name) +1、VALUES(column_name) + VALUES(column_name)、function_name(VALUES(column_name))等。
    ![](https://support.huaweicloud.com/distributed-m-comp-devg-v8-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
    上述VALUES(column_name)特性仅支持在ON DUPLICATE KEY UPDATE子句中使用。
    
  
  
  
  - 向表中字段插入单引号 " ' "时需要使用单引号自身进行转义。
  
  - 如果插入行的表达式不是正确的数据类型，系统试图进行类型转换，若转换不成功，则插入数据失败，系统返回错误信息。
   
- **DEFAULT**
  对应字段名的缺省值。如果没有缺省值，则为NULL。
  
- **query**
  一个查询语句（SELECT语句），将查询结果作为插入的数据。
  
- **RETURNING**
  返回实际插入的行，RETURNING列表的语法与SELECT的输出列表一致。
  
- **ON DUPLICATE KEY UPDATE**
  对于带有唯一约束（UNIQUE INDEX或PRIMARY KEY）的表，如果插入数据违反唯一约束，则对冲突行执行UPDATE子句完成更新，对于不带唯一约束的表，则仅执行插入。UPDATE时，可通过 "VALUES()" 来选择源数据相应的列。
  - 如果表中存在多个唯一约束，如果所插入数据违反多个唯一约束，对于检测到冲突的第一行进行更新，其他冲突行不更新（检查顺序与索引维护具有强相关性，一般先创建的索引先进行冲突检查）。
  
  - 如果插入多行，这些行均与表中同一行数据存在唯一约束冲突，则按照顺序，第一条执行插入或更新，之后依次执行更新。
  
  
  
  - 主键、唯一索引列不允许UPDATE。
  
  - expression不支持使用子查询表达式。
  
  - 如果query为子查询，则不支持使用子查询中的列名。
  
  - ON DUPLICATE KEY UPDATE子句更新多列时，前面UPDATE的结果不会影响后面的结果，且不支持同一列设置多次。
   
- **view_name**
  要插入的目标视图。
  ![](https://support.huaweicloud.com/distributed-m-comp-devg-v8-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
  对视图的插入，有如下约束：
  1. 只有直接引用基表用户列的列可插入。
  
  2. 视图必须至少包含一个可更新列，关于可更新列请参见[CREATE VIEW](https://support.huaweicloud.com/distributed-m-comp-devg-v8-gaussdb/gaussdb-81-0081.html#ZH-CN_TOPIC_0000002558805291)。
  
  3. 不支持在顶层包含DISTINCT、GROUP BY、HAVING、LIMIT、OFFSET子句的视图。
  
  4. 不支持在顶层包含集合运算（UNION以及EXCEPT）的视图。
  
  5. 不支持目标列表中包含聚集函数、窗口函数、返回集合函数（array_agg、json_agg、generate_series等）的视图。
  
  6. 不支持ON DUPLICATE KEY UPDATE功能。
  
  7. 视图中支持的表类型包括普通表、临时表、全局临时表、分区表、ustore表、astore表。
  
  8. 对多表连接视图，一次只能对一张基表做插入。
  
  9. 对连接视图插入时显式指定的插入列或隐式指定（即创建视图中指定的列）不能引用非保留键表的列。关于保留键表请参见[CREATE VIEW](https://support.huaweicloud.com/distributed-m-comp-devg-v8-gaussdb/gaussdb-81-0081.html#ZH-CN_TOPIC_0000002558805291)。
  
  10. 不支持对系统视图插入。
    
 
#### 示例
- **插入一条数据**
  **示例：**
  ```
  --建表。
  m_db=# CREATE TABLE test_t1(col1 INT,col2 VARCHAR(20));
  --插入数据。
  m_db=# INSERT INTO test_t1 (col1, col2) VALUES (1,'AB');
  --只给表中部分列插入数据。
  m_db=# INSERT INTO test_t1 (col1) VALUES (2);
  --VALUES关键字左边没有括号，右边括号里面必须严格按照表结构的顺序给所有的字段添加值。
  m_db=# INSERT INTO test_t1 VALUES (3,'AC');
  --查询表。
  m_db=# SELECT * FROM test_t1 ORDER BY col1;
   col1 | col2 
  ------+------
      1 | AB
      2 | 
      3 | AC
  (3 rows)
  --删除表。
  m_db=# DROP TABLE test_t1;
  ```
  
- **插入多条数据**
  **示例：**
  ```
  --建表。
  m_db=# CREATE TABLE test_t2(col1 INT,col2 VARCHAR(20));
  m_db=# CREATE TABLE test_t3(col1 INT,col2 VARCHAR(20));
  --插入多条数据。
  m_db=# INSERT INTO test_t2 (col1, col2) VALUES (10,'AA'),(20,'BB'),(30,'CC');
  --查询表。
  m_db=# SELECT * FROM test_t2;
   col1 | col2 
  ------+------
     10 | AA
     20 | BB
     30 | CC
  (3 rows)
  --把test_t2中的数据插入到test_t3中。
  m_db=# INSERT INTO test_t3 SELECT * FROM test_t2;
  --查询表。
  m_db=# SELECT * FROM test_t3;
   col1 | col2 
  ------+------
     10 | AA
     20 | BB
     30 | CC
  (3 rows)
  --删除表。
  m_db=# DROP TABLE test_t2;
  m_db=# DROP TABLE test_t3;
  ```
  
- **ON DUPLICATE KEY UPDATE**
  **示例：**
  ```
  -- 建表。
  m_db=# CREATE TABLE test_t4 (id INT PRIMARY KEY, info VARCHAR(10));
  m_db=# INSERT INTO test_t4 VALUES (1, 'AA'), (2,'BB'), (3, 'CC');
  -- 使用ON DUPLICATE KEY UPDATE关键字。
  m_db=# INSERT INTO test_t4 VALUES (3, 'DD'), (4, 'EE') ON DUPLICATE KEY UPDATE info = VALUES(info);
  -- 查询表。
  m_db=# SELECT * FROM test_t4;
   id | info 
  ----+------
    1 | AA
    2 | BB
    4 | EE
    3 | DD
  -- 删除表。
  m_db=# DROP TABLE test_t4;
  ```
  
- **INSERT IGNORE**
  **示例1：破坏NOT NULL约束**
  ```
  --建表。
  m_db=# CREATE TABLE test_t5(f1 INT NOT NULL);
  CREATE TABLE
  --使用IGNORE关键字。
  m_db=# INSERT IGNORE INTO test_t5 VALUES(NULL);
  WARNING:  null value in column "f1" violates not-null constraint
  DETAIL:  Failing row contains (null).
  INSERT 0 1
  --查询表。
  m_db=# SELECT * FROM test_t5;
   f1
  ----
    0
  (1 row)
  --删除表。
  m_db=# DROP TABLE test_t5;
  ```
  
  **示例2：唯一键冲突**
  ```
  --建表。
  m_db=# CREATE TABLE test_t6(f1 INT PRIMARY KEY);
  NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "test_t6_pkey" for table "test_t6"
  CREATE TABLE
  --插入数据。
  m_db=# INSERT INTO test_t6 VALUES(1);
  INSERT 0 1
  --使用IGNORE关键字。
  m_db=# INSERT IGNORE INTO test_t6 VALUES(1);
  WARNING:  duplicate key value violates unique constraint "test_t6_pkey"
  INSERT 0 0
  --查询表。
  m_db=# SELECT * FROM test_t6;
   f1
  ----
    1
  (1 row)
  --删除表。
  m_db=# DROP TABLE test_t6;
  DROP TABLE
  ```
  
  **示例3：插入的值没有找到对应的分区**
  ```
  --建表。
  m_db=# CREATE TABLE test_t7(f1 INT, f2 INT) PARTITION BY LIST(f1) (PARTITION p0 VALUES(1, 4, 7), PARTITION p1 VALUES (2, 5, 8));
  CREATE TABLE
  --使用IGNORE关键字。
  m_db=# INSERT IGNORE INTO test_t7 VALUES(3, 5);
  WARNING:  inserted partition key does not map to any table partition
  INSERT 0 0
  --查询表。
  m_db=# SELECT * FROM test_t7;
   f1 | f2
  ----+----
  (0 rows)
  --删除表。
  m_db=# DROP TABLE test_t7;
  DROP TABLE
  ```
  
  **示例4：指定分区插入时，插入的数据与指定的分区不匹配**
  ```
  --建表。
  m_db=# CREATE TABLE test_t8(f1 INT NOT NULL, f2 TEXT, f3 INT) PARTITION BY RANGE(f1)(PARTITION p0 VALUES LESS THAN(5), PARTITION p1 VALUES LESS THAN(10), PARTITION p2 VALUES LESS THAN(15), PARTITION p3 VALUES LESS THAN(MAXVALUE));
  CREATE TABLE
  --使用IGNORE关键字。
  m_db=# INSERT IGNORE INTO test_t8 PARTITION(p2) VALUES(20, 'Jan', 1);
  WARNING:  inserted partition key does not map to the table partition
  DETAIL:  N/A.
  INSERT 0 0
  --查询表。
  m_db=# SELECT * FROM test_t8;
   f1 | f2 | f3
  ----+----+----
  (0 rows)
  --删除表。
  m_db=# DROP TABLE test_t8;
  DROP TABLE
  ```
  **示例5：子查询返回多行**
  ```
  --建表。
  m_db=# CREATE TABLE test_t9(f1 INT, f2 INT);
  CREATE TABLE
  --插入数据。
  m_db=# INSERT INTO test_t9 VALUES(1, 1), (2, 2), (3, 3);
  INSERT 0 3
  --使用IGNORE关键字。
  m_db=# INSERT IGNORE INTO test_t9 VALUES((SELECT f1 FROM test_t9), 0);
  WARNING:  more than one row returned by a subquery used as an expression
  CONTEXT:  referenced column: f1
  INSERT 0 1
  --查询表。
  m_db=# SELECT * FROM test_t9 WHERE f2 = 0;
   f1 | f2
  ----+----
      |  0
  (1 row)
  --删除表。
  m_db=# DROP TABLE test_t9;
  DROP TABLE
  ```
  
- **插入视图**
  **示例：**
  ```
  --创建SCHEMA。
  m_db=# CREATE SCHEMA ins_view;
  CREATE SCHEMA
  m_db=# SET CURRENT_SCHEMA = 'ins_view';
  SET
  --创建表。
  m_db=# CREATE TABLE t1 (x1 int, y1 int);
  CREATE TABLE
  m_db=# CREATE TABLE t2 (x2 int PRIMARY KEY, y2 int);
  NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "t2_pkey" for table "t2"
  CREATE TABLE
  --创建单表视图。
  m_db=# CREATE VIEW v_ins1 AS SELECT * FROM t1;
  CREATE VIEW
  m_db=# CREATE VIEW v_ins2 AS SELECT * FROM t1 WHERE y1 < 3;
  CREATE VIEW
  --通过视图对t1插入。
  m_db=# INSERT INTO v_ins1 VALUES (1, 1);
  INSERT 0 1
  m_db=# INSERT INTO v_ins2 VALUES (5, 5);
  INSERT 0 1
  --创建多表视图。
  m_db=# CREATE VIEW vv_ins AS SELECT * FROM t1, t2 WHERE x1 = x2;
  CREATE VIEW
  --通过多表视图对t1插入。
  m_db=# INSERT INTO vv_ins (x1, y1) VALUES (2, 2);
  INSERT 0 1
  --删除SCHEMA。
  m_db=# DROP SCHEMA ins_view;
  NOTICE:  drop cascades to 5 other objects
  DETAIL:  drop cascades to table t1
  drop cascades to table t2
  drop cascades to view v_ins1
  drop cascades to view v_ins2
  drop cascades to view vv_ins
  DROP SCHEMA
  ```
  
 
#### 优化建议
- VALUES 通过insert语句批量插入数据时，建议将多条记录合并入一条语句中执行插入，以提高数据加载性能。
  例如：INSERT INTO sections VALUES (30, 'Administration', 31, 1900),(40, 'Development', 35, 2000), (50, 'Development' , 60 , 2001);
  
 
