INSERT
📄字数 10.1K
👁️阅读量 加载中...
一、关于INSERT
1.1 INSERT 概述
INSERT 是 SQL 中最基本的数据操作语句之一,用于向数据库表或视图中添加新记录。
1.2 INSERT 语法类型
当前版本下,数据库支持的 INSERT ,共分为以下几种:
- 标准INSERT语句:最基础的插入形式,支持单行、多行插入、将查询结果直接插入目标表
- 多表插入(MULTI INSERT):单语句插入多表多行数据
- 替换插入(REPLACE):主键唯一值冲突时自动替换原记录
- 忽略冲突插入(IGNORE):主键唯一值冲突时忽略报错
1.3 INSERT 使用要求
在 SQL 中,使用 INSERT 语句向表中插入数据前,需要满足以下条件:
表或视图必须存在:要插入数据的表或视图必须已经在数据库中创建
列存在性:
- 指定的列必须存在于目标表中
- 如果省略列名列表,VALUES 子句必须为表中所有列提供值
数据类型兼容性:
- 插入的值必须与对应列的数据类型兼容
- 字符串值需要用单引号括起来
约束条件:
- 如果表有约束则插入的数据必须满足表的约束条件(如 NOT NULL、PRIMARY KEY、UNIQUE 等)
- 如果列有 NOT NULL 约束且没有默认值,则必须为该列提供值
- 如果插入外键值,该值必须在引用表的主键列中存在
- 对于自增列(IDENTITY),通常不应在 INSERT 中指定值
- 字段有默认值约束时如果没有为列指定值且列有默认值定义,将使用默认值
- 如果没有默认值约束且允许 NULL,未指定值或使用 DEFAULT 关键字将使用 NULL 填充
权限要求:
- 用户必须对目标表或视图有 INSERT 权限
- 如果使用查询进行插入则用户必须对查询的目标表或视图拥有 SELECT 权限
二、INSERT语句
2.1 语法格式
2.2 标准INSERT语句
2.2.1 基本语法
详细语法结构见INSERT语法
2.2.2 核心参数
- 标准 INSERT 语法主要由
relation_expr
、insert_rest
、returning_clause
三大部分组成。 relation_expr
主要由[schema_name.] table_name | view_name
、opt_parti_clip_clause
、@link_name
组成。insert_rest
主要由insert_values
、SelectStmt
、record_val
、columnList
组成。returning_clause
主要由target_list
、BULK COLLECT
组成。
参数 | 说明 | 语法位置 |
---|---|---|
relation_expr | 插入对象,可以是表/视图 | 'INTO' relation_expr |
insert_values | 值列表 | 'VALUES' insert_values |
DEFAULT VALUES | 整行插入默认值 | 'DEFAULT' 'VALUES' |
columnList | 指定插入列 | '(' columnList ')' |
record_val | 指定记录数据 | 'VALUES' record_val |
opt_parti_clip_clause | 指定对象的分区 | table_name opt_parti_clip_clause |
SelectStmt | 查询操作 | relation_expr SelectStmt |
注意
- 此处仅展示部分引用参数,完整参数列表未全部列出
2.2.3 relation_expr
作用:当执行插入操作时,必须明确指定插入目标对象(表或视图),并支持以下可选特性:
- 1、对象类型选择:必须指定插入目标,目标可为 表(table) 或 视图(view)
- 2、表分区支持(仅当对象为表时适用):可通过
opt_parti_clip_clause
子句显式指定目标分区 - 3、指定模式(可选):可使用
schema_name.
前缀指定目标对象的所属模式 - 4、远程对象支持(可选):可通过
@link_name
语法指定远程数据库对象
示例:跨模式插入数据
sql
--向sch_test模式下的表插入数据
SQL> CREATE SCHEMA sch_test;
SQL> CREATE TABLE sch_test.tb_test(id INT);
SQL> INSERT INTO sch_test.tb_test VALUES(1);
SQL> SELECT * FROM sch_test.tb_test;
+----+
| ID |
+----+
| 1 |
+----+
SQL> DROP SCHEMA sch_test;
2.2.4 link_name
- 作用:该参数用于指定预先创建的数据库远程连接对象名称,该连接通过
CREATE DATABASE LINK
语句建立,可实现以下跨数据库操作:- 1、访问异构数据库实例的数据
- 2、访问相同数据库不同库的数据
注意
- 连接名称应符合当前数据库的命名规范
- 必须确保连接在INSERT操作时处于可用状态
- 权限要求:用户需具备远程数据库的相应访问权限
2.2.5 opt_parti_clip_clause
- 作用:显式指定要操作的分区或子分区
- 子参数:
PARTITION(parti_name)
:指定分区名称SUBPARTITION(parti_name)
:指定子分区名称
注意
- 插入数据必须符合分区键条件
- 示例:向指定分区插入数据
sql
SQL> CREATE TABLE tb_part(id INT)PARTITION BY RANGE(id) PARTITIONS(p1 VALUES LESS THAN(10),p2 VALUES LESS THAN(20));
SQL> INSERT INTO tb_part PARTITION(p1)(id) VALUES(1);
SQL> SELECT * FROM tb_part;
+----+
| ID |
+----+
| 1 |
+----+
SQL> DROP TABLE tb_part;
2.2.6 VALUES
子句
- 作用:直接指定要插入的值
- 格式:
- 简单格式:
VALUES (expr1, expr2, ..., exprn)
括号中以逗号分隔的每项可以是常值、表达式等,每项与要插入数据的列对应 - 多行格式1:
VALUES (expr1, expr2, ..., exprn),(expr1, expr2, ..., exprn),...
,用于在一条语句里插入多行数据,使用英文逗号分隔每一行插入的数据 - 多行格式2:
VALUES (expr1, expr2, ..., exprn) (expr1, expr2, ..., exprn) ...
,用于在一条语句里插入多行数据,每行插入的数据无需英文逗号分隔
- 简单格式:
- 示例:
sql
SQL> CREATE TABLE tb_vals(id INT);
SQL> INSERT INTO tb_vals VALUES(1)(2);
SQL> INSERT INTO tb_vals VALUES(3),(4);
SQL> SELECT * FROM tb_vals;
+----+
| ID |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
+----+
SQL> DROP TABLE tb_vals;
2.2.7 DEFAULT VALUES
- 作用:插入所有列的默认值,若列上未设置默认值则插入 NULL 值
- 使用场景:表上有自增列或默认值约束或所有列需要全部插入 NULL 时
注意
DEFAULT VALUES
要求表中每一列都必须有默认值,或者允许 NULL 值(此时使用 NULL 作为默认值)。如果有一列既没有默认值也不允许 NULL ,则插入会失败
- 示例:使用 DEFAULT VALUES 插入有默认值和没有默认值情况的数据
sql
SQL> CREATE TABLE tb_defs(id INT DEFAULT 10,id1 INT);
SQL> INSERT INTO tb_defs DEFAULT VALUES;
SQL> SELECT * FROM tb_defs;
+----+--------+
| ID | ID1 |
+----+--------+
| 10 | <NULL> |
+----+--------+
SQL> DROP TABLE tb_defs;
- 示例:使用 DEFAULT VALUES 插入既没有默认值也不允许 NULL 的数据
sql
SQL> CREATE TABLE tb_nul(id INT PRIMARY KEY,id1 INT DEFAULT 10);
SQL> INSERT INTO tb_nul DEFAULT VALUES;
Error: [E16005] 字段ID不能取空值
SQL> DROP TABLE tb_nul;
2.2.8 columnList
- 作用:显式指定要插入的列。在显式指定插入列的情况下,提供的值或查询结果的列数、顺序和数据类型必须与指定列完全一致或可隐式转换,否则会导致执行失败或数据异常。
- 格式:
(col1, col2,...) VALUES/SELECT...
- 示例:显式指定列名
sql
SQL> CREATE TABLE tb_cols(id INT,name VARCHAR(20));
SQL> INSERT INTO tb_cols(id) VALUES(1);
SQL> SELECT * FROM tb_cols;
+----+--------+
| ID | NAME |
+----+--------+
| 1 | <NULL> |
+----+--------+
SQL> DROP TABLE tb_cols;
2.2.9 DEFAULT
- 作用:使用
DEFAULT
关键字的作用是指定该列使用定义的默认值,默认值通常在表定义时通过DEFAULT
约束设置。如果列没有定义默认值,那么使用DEFAULT
关键字将默认插入NULL
,如果该列允许NULL,则插入NULL;如果该列不允许NULL,则报错 - 与 DEFAULT VALUES 区别:
DEFAULT VALUES
表示插入一行所有列都使用默认值,DEFAULT
指定列插入默认值 - 示例:指定列插入默认值
sql
SQL> CREATE TABLE tb_def(id INT,name VARCHAR(20) DEFAULT 'abc');
SQL> INSERT INTO tb_def VALUES(default,default);
SQL> SELECT * FROM tb_def;
+--------+------+
| ID | NAME |
+--------+------+
| <NULL> | abc |
+--------+------+
SQL> DROP TABLE tb_def;
2.2.10 %ROWTYPE
记录
- 作用:使用记录变量的值作为数据插入
- 示例:插入 RECORD 类型
sql
SQL> CREATE TABLE tb_rec(a INT,name VARCHAR(100));
SQL> INSERT INTO tb_rec VALUES(1,'123')(2,'123')(3,'345');
SQL> CREATE TABLE tb_rec1(a INT,name VARCHAR(100));
SQL> DECLARE
TYPE tb_res IS TABLE OF tb_rec%ROWTYPE;
rs tb_res;
BEGIN
SELECT * BULK COLLECT INTO rs FROM tb_rec;
FOR i IN rs.FIRST ..rs.LAST loop
INSERT INTO tb_rec1 VALUES rs(i);
END LOOP;
END;
/
SQL> SELECT * FROM tb_rec1;
+---+------+
| A | NAME |
+---+------+
| 1 | 123 |
| 2 | 123 |
| 3 | 345 |
+---+------+
SQL> DROP TABLE tb_rec1;
SQL> DROP TABLE tb_rec;
2.2.11 INTO
变量
- 作用:
INTO
后面为relation_expr
语句时表示插入数据至指定的对象,INTO
用在RETURNING
后表示指定接收返回值的变量 - 格式:
INTO var1 [, var2...]
2.2.12 BULK COLLECT
- 作用:可以一次将插入的多行数据提取到 PL/SQL 集合(如数组)中,通过一次批量获取多行数据,大大减少了 SQL 引擎和 PL/SQL 引擎之间的切换次数,从而提高性能。
- 使用场景:PL/SQL 中一次插入多行数据时可使用 BULK COLLECT 关键字
- 示例:BULK COLLECT
sql
SQL> CREATE TABLE tb_ret(id INT);
SQL> DECLARE
TYPE type_table_varchar IS TABLE OF VARCHAR;
var_chr TYPE_TABLE_VARCHAR;
BEGIN
INSERT INTO tb_ret VALUES(1)(2)(3) RETURNING id BULK COLLECT INTO var_chr;
FOR j IN 1..var_chr.COUNT() LOOP
SEND_MSG(var_chr(j));
END LOOP;
END;
/
1
2
3
SQL> SELECT * FROM tb_ret;
+----+
| ID |
+----+
| 1 |
| 2 |
| 3 |
+----+
SQL> DROP TABLE tb_ret;
2.2.13 expr
- 作用:指定插入的值列表参数,可以是列值、常数值、函数、表达式等
- 示例:指定不同类型值插入表中
sql
SQL> CREATE TABLE tb_val(id INT,name VARCHAR(20));
SQL> INSERT INTO tb_val VALUES (1001, '张三')(1002, SYSDATE)(1003,2*1.1);
SQL> SELECT * FROM tb_val;
+------+---------------------+
| ID | NAME |
+------+---------------------+
| 1001 | 张三 |
| 1002 | 2025-07-11 15:58:50 |
| 1003 | 2.2 |
+------+---------------------+
SQL> DROP TABLE tb_val;
2.2.14 SelectStmt
- 作用:将查询结果插入表中,请参阅查询语法
注意
- 查询结果列数和类型必须与目标表匹配
- 使用查询时需要具有查询相关权限
- 示例:将查询返回结果插入表中
sql
SQL> CREATE TABLE tb_sels(id INT);
SQL> INSERT INTO tb_sels SELECT 10 FROM dual;
SQL> SELECT * FROM tb_sels;
+----+
| ID |
+----+
| 10 |
+----+
SQL> DROP TABLE tb_sels;
2.3 多表插入(MULTI INSERT)
2.3.1 无条件多表插入
2.3.1.1 基本语法
详细语法结构见INSERT语法
2.3.1.2 ALL
- 作用:指示无条件将查询结果插入所有指定表
- 特点:
- 无
WHEN
条件子句 - 每行源数据都会插入到所有目标表
- 区别于
INSERT FIRST | ALL
(条件插入)
- 无
2.3.1.3 insert_into_clause
- 作用:每个插入目标表的子句,可以重复多次(至少一次),如果插入表或视图指定的列与查询字段数不一致则会抛出错误
注意
- 若省略 VALUES 子句,则直接使用 SELECT 查询结果的列值作为插入数据,此时查询列必须与目标表列定义完全匹配或通过显式列名列表指定映射关系
- 若包含 VALUES 子句且提供具体常量值(如数字、字符串),则直接插入这些指定值,SELECT 查询子句将被忽略且不会执行
- 若包含 VALUES 子句且使用表达式(如列名、函数),则从 SELECT 查询结果的当前行中获取数据计算表达式值并插入
- 示例:无条件使用查询结果插入多张表
sql
SQL> CREATE TABLE tb_all1(id INT);
SQL> CREATE TABLE tb_all2(id INT);
SQL> INSERT ALL INTO tb_all1(id) INTO tb_all2(id) SELECT level FROM dual CONNECT BY level<=200;
SQL> SELECT COUNT(*) FROM tb_all1;
+-------+
| EXPR1 |
+-------+
| 200 |
+-------+
SQL> SELECT COUNT(*) FROM tb_all2;
+-------+
| EXPR1 |
+-------+
| 200 |
+-------+
SQL> DROP TABLE tb_all1;
SQL> DROP TABLE tb_all2;
2.3.2 多表条件插入(INSERT ALL\FIRST)
2.3.2.1 基本语法
2.3.2.2 核心参数
参数 | 说明 | 语法位置 |
---|---|---|
FIRST/ALL | 插入模式 | 'INSERT' ('FIRST' | 'ALL')? |
insert_when_clause | 条件子句 | insert_when_clause_list |
insert_else_clause | ELSE子句 | insert_else_clause |
详细语法结构见INSERT语法
2.3.2.3 FIRST|ALL
- 作用:
FIRST
:- 1、对于子查询返回的每一行数据,按顺序检查 WHEN 条件;
- 2、当遇到第一个满足的 WHEN 条件时,执行该 THEN 子句对应的插入操作,然后跳过该行后续的 WHEN 条件;
- 3、如果没有任何 WHEN 条件满足,且存在 ELSE 子句,则执行 ELSE 子句对应的插入操作;
- 4、如果没有任何 WHEN 条件满足且没有 ELSE 子句,则该行不会被插入任何表中。
ALL
:- 1、对于子查询返回的每一行数据,会检查每一个 WHEN 条件(无条件插入可以看作条件始终为真);
- 2、只要条件满足,就会执行对应的插入操作, 一行数据可能被插入到多个表中(满足多个条件时);
- 3、如果存在 ELSE 子句,那么当没有任何 WHEN 条件满足时,执行 ELSE 子句对应的插入操作;
- 4、否则,该行不会被插入任何表中。
注意
- FIRST 每一行最多插入到一个表中(第一个满足条件的表)
- ALL 每一行数据可能被插入到多个表中(满足多个条件时)
- 如果条件字段和插入VALUE中的字段不在后续查询输出字段中,默认追加入查询字段
2.3.2.4 insert_when_clause
- 作用:定义插入的条件和操作语句,用于检查插入数据是否符合 WHEN 条件,可以执行的 THEN 操作,使用当前语法未指定
FIRST
或ALL
时默认为ALL
- 格式:
WHEN bool_expr THEN insert_into_clause...
2.3.2.5 insert_else_clause
- 作用:当所有 WHEN 条件都不满足时需要执行的操作,ELSE 分支为可选操作,若忽略则表示不插入任何一张表
- 格式:
ELSE insert_into_clause...
2.3.2.6 insert_into_clause
作用:定义要插入的多个目标表
格式:
INTO relation_expr [(columnList)] VALUES (values_list)...
示例:使用INSERT FIRST插入数据
sql
SQL> CREATE TABLE ins_tab1(col1 INT,col2 VARCHAR(20),col3 NUMERIC(5,2),col4 DATE);
SQL> INSERT INTO ins_tab1 VALUES(11,'AB',111.11,TO_DATE('2007-04-15','YYYY-MM-DD'))(6,'CD',222.22,TO_DATE('2008-04-15','YYYY-MM-DD'))(1,'EF',333.33,TO_DATE('2009-04-15','YYYY-MM-DD'))(4,'GH',444.44,TO_DATE('2010-04-15','YYYY-MM-DD'))(NULL,'GH',555.55,TO_DATE('2011-04-15','YYYY-MM-DD'));
SQL> CREATE TABLE ins_tab2(col1 INT,col2 VARCHAR(20),col3 NUMERIC(5,2),col4 DATE);
SQL> CREATE TABLE ins_tab3(col1 INT,col2 VARCHAR(20),col3 NUMERIC(5,2),col4 DATE);
SQL> INSERT FIRST WHEN col1>10 THEN INTO ins_tab2 VALUES(col1,col2,col3,col4) WHEN col1>3 THEN INTO ins_tab3 VALUES(col1,col2,col3,col4) SELECT col1,col2,col3,col4 FROM ins_tab1;
SQL> SELECT * FROM ins_tab2;
+------+------+--------+-------------+
| COL1 | COL2 | COL3 | COL4 |
+------+------+--------+-------------+
| 11 | AB | 111.11 | 2007-04-15 |
+------+------+--------+-------------+
SQL> SELECT * FROM ins_tab3;
+------+------+--------+-------------+
| COL1 | COL2 | COL3 | COL4 |
+------+------+--------+-------------+
| 6 | CD | 222.22 | 2008-04-15 |
| 4 | GH | 444.44 | 2010-04-15 |
+------+------+--------+-------------+
SQL> DROP TABLE ins_tab1;
SQL> DROP TABLE ins_tab2;
SQL> DROP TABLE ins_tab3;
- 示例:使用INSERT ALL插入数据
sql
SQL> CREATE TABLE ins_tab1(col1 INT,col2 VARCHAR(20),col3 NUMERIC(5,2),col4 DATE);
SQL> INSERT INTO ins_tab1 VALUES(11,'AB',111.11,TO_DATE('2007-04-15','YYYY-MM-DD'))(6,'CD',222.22,TO_DATE('2008-04-15','YYYY-MM-DD'))(1,'EF',333.33,TO_DATE('2009-04-15','YYYY-MM-DD'))(4,'GH',444.44,TO_DATE('2010-04-15','YYYY-MM-DD'))(NULL,'GH',555.55,TO_DATE('2011-04-15','YYYY-MM-DD'));
SQL> CREATE TABLE ins_tab2(col1 INT,col2 VARCHAR(20),col3 NUMERIC(5,2),col4 DATE);
SQL> CREATE TABLE ins_tab3(col1 INT,col2 VARCHAR(20),col3 NUMERIC(5,2),col4 DATE);
SQL> INSERT ALL WHEN col1>10 THEN INTO ins_tab2 VALUES(col1,col2,col3,col4) WHEN col1>3 THEN INTO ins_tab3 VALUES(col1,col2,col3,col4) SELECT col1,col2,col3,col4 FROM ins_tab1;
SQL> SELECT * FROM ins_tab2;
+------+------+--------+-------------+
| COL1 | COL2 | COL3 | COL4 |
+------+------+--------+-------------+
| 11 | AB | 111.11 | 2007-04-15 |
+------+------+--------+-------------+
SQL> SELECT * FROM ins_tab3;
+------+------+--------+-------------+
| COL1 | COL2 | COL3 | COL4 |
+------+------+--------+-------------+
| 11 | AB | 111.11 | 2007-04-15 |
| 6 | CD | 222.22 | 2008-04-15 |
| 4 | GH | 444.44 | 2010-04-15 |
+------+------+--------+-------------+
SQL> DROP TABLE ins_tab1;
SQL> DROP TABLE ins_tab2;
SQL> DROP TABLE ins_tab3;
2.4 替换插入(REPLACE)
2.4.1 基本语法
详细语法结构见INSERT语法
2.4.2 REPLACE
- 作用:当使用REPLACE语句插入数据时,若新数据违反表的唯一约束(如主键或唯一值冲突),数据库会先自动删除已存在的冲突行,然后再插入新数据;若不存在唯一值冲突,则该语句会像普通INSERT INTO语句一样直接执行插入操作
- 使用场景:插入数据同表中数据存在唯一值冲突时需要覆盖已存在记录的情况
注意
- REPLACE操作如果有冲突会在日志中记载错误信息
- 示例:REPLACE插入数据
sql
--REPLACE插入数据
SQL> CREATE TABLE tb_ins(id INT PRIMARY KEY,name VARCHAR);
SQL> REPLACE INTO tb_ins VALUES(1,'abc')(1,'one');
SQL> SELECT * FROM tb_ins;
+----+------+
| ID | NAME |
+----+------+
| 1 | one |
+----+------+
SQL> DROP TABLE tb_ins;
2.5 忽略冲突插入(IGNORE)
2.5.1 基本语法
详细语法结构见INSERT语法
2.5.2 IGNORE
- 作用:指定该参数时,插入数据违反唯一约束时忽略错误,不插入该行数据
- 使用场景:批量插入时避免因个别数据冲突导致整个操作失败
注意
- 目前仅支持跳过主键唯一值相关错误,不支持跳过数据类型不匹配等错误
- 忽略执行层检查约束信息时遇到的错误,而语法层、规划层遇到的错误依旧正常报错
- IGNORE操作如果有冲突会在日志中记载错误信息
- 示例:不使用IGNORE关键字插入数据和使用IGNORE关键字插入数据进行对比
sql
SQL> CREATE TABLE tb_ins(id INT,name VARCHAR,CONSTRAINT u_1 UNIQUE(id));
--INSERT 插入数据
SQL> INSERT INTO tb_ins VALUES(1,'abc');
SQL> INSERT INTO tb_ins VALUES(1,'one');
Error: [E13001] 违反唯一值约束
--只有第一行数据插入成功
SQL> SELECT * FROM tb_ins;
+----+------+
| ID | NAME |
+----+------+
| 1 | abc |
+----+------+
--INSERT IGNORE 插入数据
SQL> INSERT IGNORE INTO tb_ins VALUES(1,'abc');
SQL> INSERT IGNORE INTO tb_ins VALUES(1,'one');
--跳过当前两行插入
SQL> SELECT * FROM tb_ins;
+----+------+
| ID | NAME |
+----+------+
| 1 | abc |
+----+------+
--INSERT 同时插入多行数据
SQL> INSERT INTO tb_ins VALUES(3,'abc')(3,'three')(4,'abc');
Error: [E13001] 违反唯一值约束
--没有数据插入成功
SQL> SELECT * FROM tb_ins;
+----+------+
| ID | NAME |
+----+------+
| 1 | abc |
+----+------+
--INSERT IGNOR 同时插入多行数据
SQL> INSERT IGNORE INTO tb_ins VALUES(3,'abc')(3,'three')(4,'abc');
--过滤第二组错误,成功插入第一、三组数据
SQL> SELECT * FROM tb_ins;
+----+------+
| ID | NAME |
+----+------+
| 1 | abc |
| 3 | abc |
| 4 | abc |
+----+------+
SQL> DROP TABLE tb_ins;