1. INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
2. [INTO] tbl_name
3. [PARTITION (partition_name [, partition_name] ...)]
4. [(col_name [, col_name] ...)]
5. { {VALUES | VALUE} (value_list) [, (value_list)] ...
6. |
7. VALUES row_constructor_list
8. }
9. [AS row_alias[(col_alias [, col_alias] ...)]]
10. [ON DUPLICATE KEY UPDATE assignment_list]
11.
12. INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
13. [INTO] tbl_name
14. [PARTITION (partition_name [, partition_name] ...)]
15. [AS row_alias[(col_alias [, col_alias] ...)]]
16. SET assignment_list
17. [ON DUPLICATE KEY UPDATE assignment_list]
18.
19. INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
20. [INTO] tbl_name
21. [PARTITION (partition_name [, partition_name] ...)]
22. [(col_name [, col_name] ...)]
23. [AS row_alias[(col_alias [, col_alias] ...)]]
24. {SELECT ... | TABLE table_name}
25. [ON DUPLICATE KEY UPDATE assignment_list]
26.
27. value:
28. {expr | DEFAULT}
29.
30. value_list:
31. value [, value] ...
32.
33. row_constructor_list:
34. ROW(value_list)[, ROW(value_list)][, ...]
35.
36. assignment:
37. col_name = [row_alias.]value
38.
39. assignment_list:
40. assignment [, assignment] ...
INSERT 语句在现有表中插入新行。INSERT ... VALUES、INSERT ... VALUES ROW() 和 INSERT ... SET 根据显式指定的值插入行。INSERT ... SELECT 将从另一个或多个表中选择的行插入表中。在 MySQL 8.0.19 及更高版本中也可以使用 INSERT ... TABLE 语句插入单个表中的行。如果 INSERT 语句带有 ON DUPLICATE KEY UPDATE 子句,如果插入的行与唯一索引或者主键索引重复时,可以更新现有行。在 MySQL 8.0.19 及更高版本中,具有一个或多个可选列别名的行别名可以与 ON DUPLICATE KEY UPDATE 一起使用,以引用要插入的行。
在 MySQL 8.0 中,DELAYED 关键字被服务器接受但会被忽略。
向表插入数据需要该表的 INSERT 权限。如果使用了 ON DUPLICATE KEY UPDATE 子句,并且由于重复键导致更新了数据,则语句需要更新列的 UPDATE 权限。对于已读取但未修改的列,只需要 SELECT 权限(例如,对于只在 ON DUPLICATE KEY UPDATE 子句中 col_name=expr 赋值右侧引用的列)。
向分区表插入数据时,可以控制哪些分区和子分区接受新行。PARTITION 选项接受表的逗号分隔的一个或多个分区或子分区(或两者)的名称列表。如果给定 INSERT 语句要插入的任何行与列出的分区不匹配,则 INSERT 语句将失败,并出现错误提示:Found a row not matching the given partition set。
可以使用 REPLACE 而不是 INSERT 来覆盖旧行。REPLACE 是在处理包含重复旧行的唯一键值的新行时 INSERT IGNORE 语句的对应项:新行替换旧行,而不是被丢弃。
tbl_name 是应该插入行的表。指定语句为其提供值的列,如下所示:
● 在表名后面提供由括号括起来的逗号分隔的列名列表。在这种情况下,每个命名列的值必须由 VALUES 列表、VALUES ROW() 列表或 SELECT 语句提供。对于 INSERT TABLE 形式,源表中的列数必须与要插入的列数匹配。
● 如果不想为 INSERT ... VALUES 或 INSERT ... SELECT 指定列名列表,表中每列的值必须由 VALUES 列表、SELECT 语句或 TABLE 语句提供。如果不知道表中列顺序,请使用 DESCRIBE tbl_name 语句来查找。
● SET 子句通过名称和每个列的赋值显式指示列。
列值可以用几种方式给出:
● 如果未启用严格 SQL 模式,则任何未显式给定值的列都将设置为其默认值(显式或隐式)。例如,如果指定的列表没有列出表中的所有列,则未列出的列将设置为其默认值。
如果启用了严格 SQL 模式,如果 INSERT 语句没有为每个没有默认值的列指定显式值,则会引发错误。
● 如果列列表和 VALUES 列表都为空,则 INSERT 将创建一行,并将每个列设置为其默认值:
1. INSERT INTO tbl_name () VALUES();
如果未启用严格模式,MySQL 将对没有显式定义默认值的任何列使用隐式默认值。如果启用了严格模式,则如果任何列没有默认值,则会发生错误。
● 使用关键字 DEFAULT 将列显式设置为其默认值。这使得编写将值分配给除少数列之外的所有列的 INSERT 语句变得更加容易,因为这样可以避免编写不完整的 VALUES 列表,否则,必须提供与 VALUES 列表中每个值对应的列名列表。
● 如果显式插入生成的列,则唯一允许的值是 DEFAULT。
● 在表达式中,可以使用 DEFAULT(col_name) 为列 col_name 生成默认值。
● 如果表达式数据类型与列数据类型不匹配,则可能会发生提供列值的表达式 expr 的类型转换。根据列类型,转换给定值可能会导致不同的插入值。例如,在INT、FLOAT、DECIMAL(10,6) 或 YEAR 列中插入字符串 ‘1999.0e-2‘ 将分别插入值1999、19.9921、19.992100或1999。存储在 INT 和 YEAR 列中的值是1999,因为字符串到数字的转换只查看字符串初始部分中可能被视为有效整数或年份的部分。对于 FLOAT 和 DECIMAL 列,字符串到数字的转换将整个字符串视为有效的数值。
● 表达式 expr 可以引用之前在值列表中设置的任何列。例如,可以执行下面的语句,因为 col2 的值引用了 col1,而 col1 之前已经赋值了:
1. INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);
但以下语句是不合法的,因为 col1 的值引用了 col2,而 col2 在 col1 之后赋值:
1. INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);
包含 AUTO_INCREMENT 值的列会出现异常。因为 AUTO_INCREMENT 值是在其他值赋值之后生成的,赋值中对 AUTO_INCREMENT 列的任何引用都会返回 0。
使用 VALUES 语法的 INSERT 语句可以插入多行。为此,请包含多个逗号分隔列值的列表,列表用括号括起来,用逗号分隔。例如:
1. INSERT INTO tbl_name (a,b,c)
2. VALUES(1,2,3), (4,5,6), (7,8,9);
每个值列表必须包含与每行插入的值个数相同的值。以下语句无效,因为它包含一个9个值的列表,而不是每个包含三个值的三个列表:
1. INSERT INTO tbl_name (a,b,c) VALUES(1,2,3,4,5,6,7,8,9);
在此上下文中,VALUE 是 VALUES 的同义词。既不表示值列表的数量,也不表示每个列表的值的数量。无论是单个值列表还是多个列表,都可以使用,与每个列表中的值的数量无关。
使用 VALUES ROW() 语法的 INSERT 语句也可以插入多行。在这种情况下,每行的值都必须包含在 ROW() 中(行构造器):
1. INSERT INTO tbl_name (a,b,c)
2. VALUES ROW(1,2,3), ROW(4,5,6), ROW(7,8,9);
可以使用 ROW_COUNT() SQL 函数或 mysql_affected_rows() C API 函数获取 INSERT 语句的影响行数。
如果使用 INSERT ... VALUES 或者有多个值列表的 INSERT ... VALUES ROW() 语句,或 INSERT ... SELECT、INSERT ... TABLE 中,语句将返回以下格式的信息字符串:
1. Records: N1 Duplicates: N2 Warnings: N3
如果使用的是 C API,则可以通过调用 mysql_info() 函数来获取信息字符串。
Records 表示语句处理的行数。(这不一定是实际插入的行数,因为重复项可能不为零。)Duplicates 表示无法插入的行数,因为它们与某些现有的唯一索引值重复。Warnings 表示尝试插入在某些方面有问题的列值的次数。在以下任何情况下都可能出现警告:
● 向已声明为 NOT NULL 的列中插入 NULL。对于多行 INSERT 语句或 INSERT INTO ... SELECT 语句,列被设置为列数据类型的隐式默认值。数字类型为0,字符串类型为空字符串(‘‘),日期和时间类型为“zero”。INSERT INTO ... SELECT 语句的处理方式与多行插入相同,因为服务器不会检查 SELECT 的结果集是否返回单行。(对于单行 INSERT,将 NULL 插入 NOT NULL 列时不会出现警告。相反,该语句将失败并提示错误。)
● 将数值列设置为列范围之外的值。该值将被剪裁到范围最接近的极值。
● 将值(如‘10.34 a‘)分配给数值列。去掉尾部的非数字文本并插入剩余的数字部分。如果字符串值没有前导数字部分,则将列设置为0。
● 将超过列最大长度的字符串插入列(CHAR、VARCHAR、TEXT 或 BLOB),值被截断为列的最大长度。
● 在日期或时间列中插入数据类型非法的值。该列被设置为相应类型的适当零值。
● 如果 INSERT 语句向有 AUTO_INCREMENT 列的表中插入一行,可以使用 LAST_INSERT_ID() SQL 函数或 mysql_INSERT_ID() C API 函数来查找该列使用的值。
INSERT 语句支持以下修饰符:
● 如果使用 LOW_PRIORITY 修饰符,INSERT 的执行将被延迟,直到没有其他客户端从表中读取数据。这包括在现有客户端读取时已经在读的其他客户端,以及正在等待的 INSERT LOW_PRIORITY 语句。因此,发出 INSERT LOW_PRIORITY 语句的客户端可能要等待很长时间。
低优先级只影响只使用表级锁定(如 MyISAM、MEMORY 和 MERGE)的存储引擎。
● 如果指定 HIGH_PRIORITY,则它会覆盖 --low-priority-updates 选项(如果服务器是用该选项启动的)的设置。它还导致不使用并发插入。
HIGH_PRIORITY 只影响只使用表级锁定(如 MyISAM、MEMORY 和 MERGE)的存储引擎。
● 如果使用 IGNORE 修饰符,则会忽略执行 INSERT 语句时发生的可忽略错误。例如,没有 IGNORE,如果行与表中现有的唯一索引或主键值重复,则会引发重复键错误,语句将中止。使用 IGNORE,将丢弃该行,不会报错。忽略的错误会生成警告。
插入分区表时没有找到与给定分区值匹配的值,IGNORE 也有类似的效果。没有 IGNORE,这样的 INSERT 语句将因错误而中止。使用 INSERT IGNORE 时,对于包含不匹配值的行,INSERT 操作将失败而不报错,但会插入匹配的行。
如果未指定 IGNORE,触发错误的数据转换将中止语句。使用 IGNORE,无效值将调整为最接近的值并插入;将生成警告,但语句不会中止。可以使用 mysql_info() C API 函数确定表中实际插入了多少行。
● 指定 ON DUPLICATE KEY UPDATE,如果插入的行会导致唯一索引或主键中出现重复值,则会更新旧行。如果将行作为新行插入,则每行受影响的行值为 1;如果更新现有行,则每行的受影响行值为 2;如果将现有行设置为当前值,则每行的受影响行值为 0。如果在连接到 mysqld 时将 CLIENT_FOUND_ROWS 标志指定给 mysql_real_connect() C API 函数,则如果将现有行设置为其当前值,则受影响的行值为 1(而不是0)。
● INSERT DELAYED 在 MySQL 5.6 中被弃用,并计划最终删除。在 MySQL 8.0 中,接受 DELAYED 修饰符,但实际不起作用。使用 INSERT(无 DELAYED)代替。