15.2.7 插入语句
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ... }
[AS row_alias[(col_alias [, col_alias] ...)]]
[ON DUPLICATE KEY UPDATE assignment_list]
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
SET assignment_list
[AS row_alias[(col_alias [, col_alias] ...)]]
[ON DUPLICATE KEY UPDATE assignment_list]
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{ SELECT ...
| TABLE table_name
| VALUES row_constructor_list
}
[ON DUPLICATE KEY UPDATE assignment_list]
value:
{expr | DEFAULT}
value_list:
value [, value] ...
row_constructor_list:
ROW(value_list)[, ROW(value_list)][, ...]
assignment:
col_name =
value
| [row_alias.]col_name
| [tbl_name.]col_name
| [row_alias.]col_alias
assignment_list:
assignment [, assignment] ...
INSERT
将新行插入到现有表中。INSERT ... VALUES
、INSERT ... VALUES ROW()
和INSERT ... SET
语句形式根据明确指定的值插入行。INSERT ... SELECT
形式从另一个表或表中选择行插入。你也可以使用INSERT ... TABLE
将单个表中的行插入。INSERT
与ON DUPLICATE KEY UPDATE
子句使得可以更新现有行,如果要插入的行将导致在唯一索引或主键中出现重复值。使用ON DUPLICATE KEY UPDATE
可以与行别名和一个或多个可选列别名一起使用,以引用要插入的行。
关于INSERT ... SELECT
和INSERT ... ON DUPLICATE KEY UPDATE
的详细信息,请参见第15.2.7.1节,“INSERT ... SELECT Statement”和第15.2.7.2节,“INSERT ... ON DUPLICATE KEY UPDATE Statement”。
在MySQL 8.4中,DELAYED
关键字被服务器接受,但忽略。关于这个原因,请参见第15.2.7.3节,“INSERT DELAYED Statement”。
将数据插入表中需要对该表拥有INSERT
权限。如果使用了ON DUPLICATE KEY UPDATE
子句,并且存在重复键导致UPDATE操作被执行,而不是INSERT操作,那么该语句需要对要更新的列拥有UPDATE
权限。对于只读但未修改的列,您需要拥有SELECT
权限(例如,对于在ON DUPLICATE KEY UPDATE子句中仅在右侧使用的列)。
在插入分区表时,您可以控制哪些分区和子分区接受新的行。PARTITION
子句将一个逗号分隔的列表作为参数,该列表包含要插入的表的一或多个分区或子分区(或两者)的名称。如果给定的INSERT
语句中的某些行不匹配其中之一的分区,INSERT
语句将失败,并返回错误Found a row not matching the given partition set。更多信息和示例,请见第26.5节,“分区选择”。
tbl_名
是要插入行的表。指定语句提供值的列名如下:
-
在表名前添加一个括号列表,逗号分隔的列名。在这种情况下,每个命名列都必须由
VALUES
列、VALUES ROW()
列或SELECT
语句提供值。对于INSERT TABLE
形式,源表的列数必须与要插入的列数相匹配。 -
如果您不指定
INSERT ... VALUES
或INSERT ... SELECT
的列名列表,必须为表中的每一列提供值,可以通过VALUES
列表、SELECT
语句或TABLE
语句提供。如果您不知道表中的列顺序,可以使用DESCRIBE
来确定。tbl_name
-
一个
SET
子句通过列名和要分配给每一列的值来明确地指定列。
可以以多种方式提供列值:
-
如果不启用严格SQL模式,任何未明确指定值的列将被设置为其默认值(显式或隐式)。例如,如果您指定了一个列列表,但该列表中没有命名所有表中的列,那么未命名的列将被设置为其默认值。默认值分配在第13.6节,“数据类型默认值”中描述。
如果启用了严格SQL模式,
INSERT
语句将生成错误,如果它没有指定明确值为每一列都没有默认值的列。请参阅第7.1.11节,“服务器SQL模式”。 -
如果同时为空,
INSERT
创建一个行,其中每个列设置为其默认值:INSERT INTO tbl_name () VALUES();
如果严格模式未启用,MySQL 使用隐式默认值来填充任何没有明确定义的默认值的列。如果启用了严格模式,则在任何列没有默认值时发生错误。
-
使用关键字
DEFAULT
将列设置为其默认值。这使得编写INSERT
语句更容易,因为它允许您避免编写不完整的VALUES
列表,而是可以指定所有列的名称。否则,您必须提供与VALUES
列表对应的每个列名。 -
如果生成列被明确插入,唯一允许的值是
DEFAULT
。关于生成列的信息,请见第15.1.20.8节,“CREATE TABLE and Generated Columns”。 -
在表达式中,您可以使用
DEFAULT(
来产生列col_名
)col_名
的默认值。 -
表达式类型转换
expr
可能会发生,如果表达式数据类型不匹配列数据类型。将给定的值转换可以根据列类型导致不同的插入值。例如,将字符串'1999.0e-2'
插入到INT
、FLOAT
、DECIMAL(10,6)
或YEAR
列中将插入值1999
、19.9921
、19.992100
或1999
, 分别。存储在INT
和YEAR
列中的值是1999
, 因为字符串到数字转换只考虑初始部分的有效整数或年份。对于FLOAT
和DECIMAL
列,字符串到数字的转换将整个字符串视为一个有效的数字值。 -
表达式
expr
可以引用任何先前在值列表中设置的列。例如,您可以这样做,因为col2
的值引用了col1
,该值已经被分配:INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);
然而,以下语句不合法,因为对
col1
的值引用了col2
col1
被赋值后的:INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);
对于包含
AUTO_INCREMENT
值的列,会出现异常。因为AUTO_INCREMENT
值是在其他值分配后生成的,所以对AUTO_INCREMENT
列在赋值中的引用将返回一个0
。
INSERT
语句使用VALUES
语法可以插入多行。要实现这个,包括多个逗号分隔的列值列表,其中每个列表用括号括起来并用逗号分隔。示例:
INSERT INTO tbl_name (a,b,c)
VALUES(1,2,3), (4,5,6), (7,8,9);
每个值列表必须包含将要插入每行的确切数量的值。以下语句无效,因为它包含一个九个值的列表,而不是三个值列表每个三值:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3,4,5,6,7,8,9);
VALUE
是VALUES
在这个上下文中的同义词。它们都没有暗示关于值列表数量或每个列表中的值数量的信息。任何一个可以用来是否有单个值列表或多个列表,以及无论每个列表中的值数量如何。
INSERT
语句使用VALUES ROW()
语法也可以插入多行。在这种情况下,每个值列表都必须包含在一个ROW()
(row constructor)中,如下:
INSERT INTO tbl_name (a,b,c)
VALUES ROW(1,2,3), ROW(4,5,6), ROW(7,8,9);
对INSERT
语句的affected-rows值可以使用ROW_COUNT()
SQL函数或mysql_affected_rows()
C API函数获取。请参阅第14.15节,“信息函数”,和mysql_affected_rows()。
如果您使用INSERT ... VALUES
或INSERT ... VALUES ROW()
多个值列表,或者INSERT ... SELECT
或INSERT ... TABLE
,语句将返回以下格式的信息字符串:
Records: N1 Duplicates: N2 Warnings: N3
如果您使用C API,可以通过调用mysql_info()
函数获取信息字符串。请参阅mysql_info()。
Records
表示语句处理的行数。 (这不一定是实际插入的行数,因为Duplicates
可以为非零值。) Duplicates
表示由于将要插入的行与现有唯一索引值重复而不能插入的行数。 Warnings
表示尝试插入列值但存在某些问题的次数。警告可以在以下任何情况下出现:
-
将
NULL
插入到已声明为NOT NULL
的列中。对于多行INSERT
语句或INSERT INTO ... SELECT
语句,列将被设置为该列数据类型的隐式默认值。对于数值类型,这是0
;对于字符串类型,这是空字符串(''
);对于日期和时间类型,这是“零”值。多行INSERT INTO ... SELECT
语句的处理方式与多行插入相同,因为服务器不检查来自SELECT
的结果集以确定是否返回单行。 (对于单行INSERT
,在将NULL
插入到NOT NULL
列时,不会出现警告,而是语句失败并返回错误。) -
将数值列设置为超出该列范围的值。该值将被截断到最近的边界。
-
将字符串值,如
'10.34 a'
,赋值给数值列。尾部非数字文本将被删除,剩余的数字部分将被插入。如果字符串值没有前导数字部分,则该列将被设置为0
。 -
将字符串插入到字符串列(
CHAR
、VARCHAR
、TEXT
或BLOB
),该值超过列的最大长度。该值将被截断到列的最大长度。 -
将非法值插入到日期或时间列中,该列将被设置为相应的零值类型。
-
有关
INSERT
示例涉及到AUTO_INCREMENT
列值,请参阅第5.6.9节,“使用 AUTO_INCREMENT”。如果使用
INSERT
语句将行插入到具有AUTO_INCREMENT
列的表中,您可以使用LAST_INSERT_ID()
SQL函数或mysql_insert_id()
C API函数来找到用于该列的值。Note这两个函数不总是行为一致。关于
INSERT
语句对AUTO_INCREMENT
列的行为,详见第14.15节,“信息函数”,和mysql_insert_id()。
INSERT语句支持以下修饰符:
-
如果使用
LOW_PRIORITY
修饰符,执行INSERT
语句将被延迟,直到没有其他客户端正在读取该表。这包括其他客户端,即使它们在现有客户端读取时开始读取,以及等待INSERT LOW_PRIORITY
语句的执行。因此,对于使用INSERT LOW_PRIORITY
语句的客户端来说,可能需要等待很长时间。LOW_优先级
只对使用表锁定的存储引擎(如MyISAM
、MEMORY
和MERGE
)生效。NoteLOW_优先级
通常不应该与MyISAM
表一起使用,因为这样会禁用并发插入。请参阅第10.11.3节,“并发插入”。 -
如果您指定
HIGH_优先级
,它将覆盖服务器启动时的--low-priority-updates
选项的效果,并且会导致并发插入不被使用。请参阅第10.11.3节,“并发插入”。HIGH_优先级
只对使用表锁定的存储引擎(如MyISAM
、MEMORY
和MERGE
)生效。 -
如果您使用
IGNORE
修饰符,执行INSERT
语句时出现的可忽略错误将被忽略。例如,在没有IGNORE
时,重复一个唯一索引或主键值的行会导致重复键错误并且语句被中止。在使用IGNORE
时,这个行将被丢弃,并且不会出现错误。忽略的错误将生成警告而不是错误。忽略
对于插入到分区表中没有找到匹配值的行具有相似的效果。没有忽略
,这样的INSERT
语句将因错误而被中止。当使用INSERT IGNORE
时,插入操作对包含未匹配值的行失败,但对匹配行进行插入。例如,请参见第26.2.2节,“LIST 分区”。如果不指定
忽略
,可能会导致错误的数据转换语句中止。使用忽略
,无效值将被调整到最近的值并插入;警告将被产生,但语句不会中止。你可以使用mysql_info()
C API函数来确定实际插入到表中的行数。更多信息,请参见忽略语句的执行效果。
您可以使用
REPLACE
而不是INSERT
来覆盖老的行。REPLACE
是INSERT IGNORE
的对应项,在处理包含唯一键值的新行时,它们将替换老的行,而不是被丢弃。请参阅第15.2.12节,“REPLACE 语句”。 -
如果您指定了
ON DUPLICATE KEY UPDATE
,并且插入了一行该将导致在唯一索引或主键中出现重复值,那么对老的行将进行UPDATE
。每行受影响的行数是1,如果插入了一行新行,2如果更新了现有行,0如果现有行保持不变。如果您在连接到mysqld时指定了CLIENT_FOUND_ROWS
标志到mysql_real_connect()
C API函数,那么受影响的行数将是1(而不是0)如果现有行保持不变。请参阅第15.2.7.2节,“INSERT ... ON DUPLICATE KEY UPDATE 语句”。 -
INSERT DELAYED 在 MySQL 5.6 中被弃用,计划最终删除。在 MySQL 8.4 中,
DELAYED
修饰符被接受但被忽略。请使用INSERT
(不带DELAYED
) 替代。详见第15.2.7.3节,“INSERT DELAYED 语句”。