一次INSERT插入多行应使用单条语句、多组圆括号VALUES并用英文逗号分隔,字段顺序与数量须严格一致,各数据库均支持;需注意类型匹配(PostgreSQL更严格)、长度限制(建议≤1000行)及避免隐式转换。

INSERT INTO ... VALUES 一次插多行怎么写
直接用逗号分隔多组 VALUES,一行 INSERT 语句搞定,不是写多个 INSERT。这是最标准、最高效的方式,所有主流 SQL 数据库(MySQL、PostgreSQL、SQL Server、SQLite)都支持。
常见错误是把多行当成多个独立语句拼在一起,结果报错或只插入第一行;或者误以为必须用 UNION ALL 或临时表——完全没必要。
- 每组值用圆括号包裹,之间用英文逗号分隔
- 列名列表只写一次,在
INSERT INTO table_name (col1, col2)中明确指定 - 每组
VALUES的字段顺序和数量必须严格一致 - 字符串值用单引号,
NULL不加引号,数字不加引号
示例:
INSERT INTO users (name, age, status)
VALUES ('Alice', 28, 'active'),
('Bob', 35, 'inactive'),
('Charlie', 31, 'active');
MySQL 和 PostgreSQL 对多行 VALUES 的兼容性差异
语法一样,但行为细节有坑。MySQL 默认允许空值或类型隐式转换,PostgreSQL 更严格——比如把字符串 '123' 插入 INT 字段,在 PostgreSQL 会直接报错 ERROR: column "age" is of type integer but expression is of type text,而 MySQL 可能默默转成 123。
- PostgreSQL 要求每组
VALUES中对应位置的数据类型完全匹配目标列 - MySQL 在严格模式(
STRICT_TRANS_TABLES)下也会报错,但默认可能容忍 - 如果某列有默认值或允许
NULL,对应位置可显式写DEFAULT或NULL,但不能留空
别依赖自动转换,显式写清楚更安全:
INSERT INTO logs (level, message, created_at)
VALUES ('ERROR', 'timeout', DEFAULT),
('INFO', 'started', NOW());
VALUES 列表太长会不会出问题
会。不是语法问题,是数据库连接层或服务端的限制在起作用。比如 MySQL 的 max_allowed_packet 默认一般只有 4MB,插几万行字符串很容易超;PostgreSQL 的 statement_timeout 或内存限制也可能中断大语句。
- 单条
INSERT建议控制在 1000 行以内,兼顾性能和稳定性 - 超过时拆成多个语句,不要硬扛——拆分比调大配置更可控
- 批量导入优先考虑
LOAD DATA INFILE(MySQL)或COPY(PostgreSQL),它们专为大数据设计,比VALUES快一个数量级 - ORM 框架(如 SQLAlchemy、Django ORM)生成的多行
VALUES通常自带分批逻辑,留意它默认的batch_size
为什么不用 INSERT ... SELECT 或 WITH 代替 VALUES
可以,但没必要。除非你在动态构造数据(比如从另一张表查出结果再插),否则纯静态多行插入,VALUES 最直白、执行计划最简单、调试最方便。
-
INSERT ... SELECT多一层查询解析开销,还容易因子查询为空导致没插入任何行而不报错 -
WITHCTE 写法更重,可读性反而下降,且 SQLite 直到 3.8.3 才支持,老版本直接报错near "WITH": syntax error - 有些数据库对嵌套 CTE + 多行插入的优化不如原生
VALUES,实测慢 10%~20%
真要动态生成,也建议先拼好 VALUES 列表,而不是强行套 SELECT。
多行 VALUES 看似简单,但字段对齐、类型匹配、长度控制这三处最容易在上线后突然崩——尤其是跨环境迁移时,MySQL 开发机宽松,PostgreSQL 生产库严格,一跑就挂。










