Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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 ... VALUESINSERT ... VALUES ROW()INSERT ... SET 语句形式根据明确指定的值插入行。INSERT ... SELECT 形式从另一个表或表中选择行插入。你也可以使用INSERT ... TABLE 将单个表中的行插入。INSERTON DUPLICATE KEY UPDATE 子句使得可以更新现有行,如果要插入的行将导致在唯一索引或主键中出现重复值。使用ON DUPLICATE KEY UPDATE 可以与行别名和一个或多个可选列别名一起使用,以引用要插入的行。

关于INSERT ... SELECTINSERT ... 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 ... VALUESINSERT ... 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'插入到INTFLOATDECIMAL(10,6)YEAR列中将插入值199919.992119.9921001999, 分别。存储在INTYEAR列中的值是1999, 因为字符串到数字转换只考虑初始部分的有效整数或年份。对于FLOATDECIMAL列,字符串到数字的转换将整个字符串视为一个有效的数字值。

  • 表达式expr可以引用任何先前在值列表中设置的列。例如,您可以这样做,因为col2的值引用了col1,该值已经被分配:

    INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);

    然而,以下语句不合法,因为对col1的值引用了col2col1被赋值后的:

    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);

VALUEVALUES在这个上下文中的同义词。它们都没有暗示关于值列表数量或每个列表中的值数量的信息。任何一个可以用来是否有单个值列表或多个列表,以及无论每个列表中的值数量如何。

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 ... VALUESINSERT ... VALUES ROW()多个值列表,或者INSERT ... SELECTINSERT ... 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

  • 将字符串插入到字符串列(CHARVARCHARTEXTBLOB),该值超过列的最大长度。该值将被截断到列的最大长度。

  • 将非法值插入到日期或时间列中,该列将被设置为相应的零值类型。

  • 有关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_优先级 只对使用表锁定的存储引擎(如 MyISAMMEMORYMERGE)生效。

    Note

    LOW_优先级 通常不应该与 MyISAM 表一起使用,因为这样会禁用并发插入。请参阅第10.11.3节,“并发插入”

  • 如果您指定 HIGH_优先级,它将覆盖服务器启动时的 --low-priority-updates 选项的效果,并且会导致并发插入不被使用。请参阅第10.11.3节,“并发插入”

    HIGH_优先级 只对使用表锁定的存储引擎(如 MyISAMMEMORYMERGE)生效。

  • 如果您使用 IGNORE 修饰符,执行INSERT 语句时出现的可忽略错误将被忽略。例如,在没有 IGNORE 时,重复一个唯一索引或主键值的行会导致重复键错误并且语句被中止。在使用 IGNORE 时,这个行将被丢弃,并且不会出现错误。忽略的错误将生成警告而不是错误。

    忽略 对于插入到分区表中没有找到匹配值的行具有相似的效果。没有忽略,这样的INSERT语句将因错误而被中止。当使用INSERT IGNORE时,插入操作对包含未匹配值的行失败,但对匹配行进行插入。例如,请参见第26.2.2节,“LIST 分区”

    如果不指定忽略,可能会导致错误的数据转换语句中止。使用忽略,无效值将被调整到最近的值并插入;警告将被产生,但语句不会中止。你可以使用mysql_info()C API函数来确定实际插入到表中的行数。

    更多信息,请参见忽略语句的执行效果

    您可以使用REPLACE而不是INSERT来覆盖老的行。REPLACEINSERT 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 语句”