1. INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
2. [INTO] tbl_name
3. [PARTITION (partition_name [, partition_name] ...)]
4. [(col_name [, col_name] ...)]
5. {SELECT ... | TABLE table_name}
6. [ON DUPLICATE KEY UPDATE assignment_list]
7.
8. value:
9. {expr | DEFAULT}
10.
11. assignment:
12. col_name = value
13.
14. assignment_list:
15. assignment [, assignment] ...
使用 INSERT ... SELECT 语句,可以从 SELECT 语句的结果中快速地将许多行插入到表中,该语句可以从一个或多个表中进行选择。例如:
1. INSERT INTO tbl_temp2 (fld_id)
2. SELECT tbl_temp1.fld_order_id
3. FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;
从 MySQL 8.0.19 开始,可以用 TABLE 语句代替 SELECT,如下所示:
1. INSERT INTO ta TABLE tb;
TABLE tb 相当于 SELECT * FROM tb。当将源表中的所有列插入到目标表中,并且不需要使用 WHERE 进行筛选时,它非常有用。此外,可以使用 ORDER BY 按一个或多个列对表中的行进行排序,并且可以使用 LIMIT 子句限制插入的行数。
以下条件适用于 INSERT ... SELECT 语句,除非另有说明,否则也适用于 INSERT ... TABLE:
● 指定 IGNORE 以忽略可能导致重复键冲突的行。
● INSERT 语句的目标表可以出现在查询的 SELECT 部分的 FROM 子句中,也可以是 TABLE 指定的表。但是,不能在子查询中插入一个表并从同一表中进行选择。
当从同一个表中进行选择和插入时,MySQL 会创建一个内部临时表来保存 SELECT 中的行,然后将这些行插入到目标表中。但是,当t是临时表时,不能使用 INSERT INTO t ... SELECT ... FROM t 语句。因为在同一语句中不能引用两次临时表。出于同样的原因,当t是临时表时,不能使用 INSERT INTO t ... TABLE t 语句。
● AUTO_INCREMENT 列工作正常。
● 为了确保二进制日志可以用来重新创建原始表,MySQL 不允许 INSERT ... SELECT 或 INSERT ... TABLE 语句并发插入。
● 为避免 SELECT 和 INSERT 引用同一个表时出现不明确的列引用问题,请为 SELECT 部分中使用的每个表提供一个唯一的别名,并使用适当的别名限定该部分中的列名。
TABLE 语句不支持别名。
通过表名及后面的 PARTITION 选项可以显式地选择使用源表或目标表(或两者)的哪些分区或子分区(或两者)。在语句的 SELECT 部分 PARTITION 与源表的名称一起使用时,只从其分区列表中指定的分区或子分区中选择行。当 PARTITION 与目标表的名称一起用于语句的 INSERT 部分时,必须能够将所选的所有行插入到选项后面的分区列表中指定的分区或子分区中。否则 INSERT ... SELECT 语句失败。
TABLE 不支持 PARTITION 选项。
不带 ORDER BY 子句的 SELECT 或 TABLE 语句返回行的顺序是不确定的。这意味着,在使用复制时,不能保证这样的 SELECT 在主服务器和从服务器上以相同的顺序返回行,这可能会导致它们之间的不一致。要防止这种情况发生,请确保用于复制的 INSERT ... SELECT 或 INSERT ... TABLE 语句要使用 ORDER BY 子句在主服务器和从服务器上能生成相同的行顺序。
由于这个问题,对于基于语句的复制,INSERT ... SELECT ON DUPLICATE KEY UPDATE 和 INSERT IGNORE ... SELECT 语句被标记为不安全。当使用基于语句的模式时,此类语句在错误日志中生成警告,在使用 MIXED 模式时,这些语句将使用基于行的格式写入二进制日志。
官方文档:
https://dev.mysql.com/doc/refman/8.0/en/insert-select.html