多行插入需用逗号分隔多组圆括号,postgresql/sql server/mysql 8.0.19+支持;旧版mysql报错,须改用union all或单条语句。

VALUES子句支持多行插入,但语法有严格要求
SQL标准(及主流数据库如PostgreSQL、SQL Server、SQLite)允许在INSERT INTO ... VALUES中用逗号分隔多组括号,一次性写入多行。但MySQL 8.0.19+才原生支持该语法;旧版MySQL会报错ERROR 1064,必须改用UNION ALL或分多条语句。
正确写法示例(兼容PostgreSQL/SQL Server/新版MySQL):
INSERT INTO users (id, name, status) VALUES (1, 'Alice', 'active'), (2, 'Bob', 'inactive'), (3, 'Charlie', 'pending');
- 每组值必须用圆括号包裹,且括号间仅用英文逗号分隔,末尾不能加逗号
- 列名列表与每组值的顺序、数量、类型必须严格一致
- 字符串值需用单引号,
NULL直接写,不加引号
MySQL旧版本(
老版MySQL解析器不接受多组VALUES,强行使用会触发ERROR 1064: You have an error in your SQL syntax。此时可改用SELECT ... UNION ALL构造数据集:
INSERT INTO users (id, name, status) SELECT 1, 'Alice', 'active' UNION ALL SELECT 2, 'Bob', 'inactive' UNION ALL SELECT 3, 'Charlie', 'pending';
-
UNION ALL比UNION快,避免去重开销 - 所有
SELECT的列数、类型需对齐,否则报ERROR 1222 - 若表有自增主键,且想显式插入
id,确保表未启用sql_mode=NO_AUTO_VALUE_ON_ZERO等限制
VALUES多行插入时NULL和默认值的处理
显式写NULL表示插入空值;省略某列为“不指定”,是否触发默认值取决于列定义和SQL模式。例如:
INSERT INTO logs (event_time, message, level)
VALUES
('2024-01-01 10:00:00', 'startup', DEFAULT),
('2024-01-01 10:05:00', NULL, 'WARN');
-
DEFAULT关键字会让该列使用建表时定义的DEFAULT值(如CURRENT_TIMESTAMP) - 写
NULL是明确插入空值,和“不写该列”语义不同——后者可能触发默认值,也可能报错(如该列NOT NULL且无默认值) - PostgreSQL中可写
DEFAULT,MySQL只支持列级默认值,不支持VALUES里用DEFAULT关键字(会报错)
批量插入性能与事务边界要注意
单条INSERT ... VALUES (..),(..)比多条单行INSERT快得多,因为减少网络往返和日志刷盘次数。但别忽略事务控制:
- 大批次(如上万行)建议拆成每千行一个
INSERT,避免锁表太久或事务日志暴涨 - 务必在事务中执行:
BEGIN; INSERT ... ; COMMIT;,否则每条INSERT自动提交,性能断崖下跌 - SQLite默认
AUTO_COMMIT开启,必须显式BEGIN,否则多行VALUES实际仍是逐条提交
真正容易被忽略的是:不同数据库对“一行VALUES能写多少列/值”有硬限制(如PostgreSQL默认max_locks_per_transaction间接影响,SQL Server有参数query governor cost limit),超长语句可能静默截断或报错,测试时务必用真实字段数压测。











