首页/数据/SQL 速查/INSERT VALUES 插入数据
变更与事务52 条

INSERT VALUES 插入数据

按列清单逐行或多行插入:显式列出列名可读且抗表结构变更;多行 VALUES 明显减少网络往返。

SQL 速查数据更新于 2026-10-13

INSERT VALUES 是什么

INSERT … VALUES 按列清单插入一行或多行数据。显式写出列名比依赖表的列顺序更抗结构变更:加列、调整列顺序都不会让插入错位。多行 VALUES 一次写入比循环单行插入少掉大量网络往返与事务开销,是批量导入的首选写法。自增主键列应留空或写 NULL 交给数据库生成,有默认值的列可以省略。批量规模要控制,单条语句过大会触碰 max_allowed_packet 之类的上限,失败时也会整批回滚。

基本信息

基本语法INSERT INTO 表 (列1, 列2) VALUES (值1, 值2)
多行插入VALUES (…), (…), (…) 一条语句写多行
列清单建议显式写出;省略时按表定义顺序,结构变化容易错位
自增列留空或写 NULL 由数据库生成,显式写值会推进自增计数器
默认值省略该列或用 DEFAULT 关键字,让表默认值生效
平台差异冲突处理写法不同:MySQL 用 IGNORE 或 ON DUPLICATE KEY,PostgreSQL 用 ON CONFLICT

典型使用场景

  • 初始化测试数据:一条语句插入多行,脚本简洁易读
  • 批量导入:从 CSV 或上游系统导数据入库
  • 不重复插入:MySQL 用 INSERT IGNORE,PostgreSQL 用 ON CONFLICT DO NOTHING
  • 存在则更新:改用 upsert 语法,一条语句完成判断
  • 小批量数据迁移:字段对齐后直接写入目标表
  • 初始化默认行:新用户注册时补一条配置记录

示例

示例
INSERT INTO users (name, email, city, status)        # 显式列清单
VALUES ('Li Lei',  'li@example.com',  'Beijing',  1),  # 第一行
       ('Han Mei',  'han@example.com', 'Shanghai', 1),  # 第二行
       ('Wang Wu',  NULL,              'Chengdu',  0);  # NULL 要求该列允许为空

-- 只写部分列,其余走表默认值
INSERT INTO users (name, created_at) VALUES ('Zhao Liu', NOW());

冲突处理与分批

冲突处理与分批
-- MySQL:遇到重复键跳过
INSERT IGNORE INTO users (name, email) VALUES ('A', 'a@x.com');

-- PostgreSQL:无重复时才插入
INSERT INTO users (name, email) VALUES ('A', 'a@x.com')
ON CONFLICT (email) DO NOTHING;

-- 大批量插入改成分批执行,每批 500 到 1000 行
INSERT INTO t (a, b) VALUES (1, 2), (3, 4);   # 循环分批重复执行

-- 从查询结果插入,注意列数与类型对齐
INSERT INTO archive_orders (id, amount) SELECT id, amount FROM orders WHERE created_at < '2023-01-01';

插入写法与语义

写法语义注意
INSERT INTO … VALUES插入新行唯一键冲突直接报错
INSERT IGNORE冲突跳过MySQL 专有,也会忽略其它错误
ON CONFLICT DO NOTHING冲突跳过PostgreSQL 的标准写法
ON DUPLICATE KEY UPDATE冲突时更新MySQL 专有,冲突也会消耗自增值
INSERT … SELECT从查询结果插入列数与顺序必须对齐
REPLACE INTO先删后插MySQL 专有,会触发删除并丢默认值
多行 VALUES 比多条单行 INSERT 快得多,原因是解析一次、网络往返一次、事务提交一次;但也别把几十万行塞进一条语句,分批更稳妥。
省略列清单时插入依赖表的列顺序,后续加列或调整顺序可能让数据写进错误的列,生产脚本一律显式列出列名。
MySQL 的 INSERT IGNORE 会把所有错误降级为告警,不只是重复键,数据被截断或类型转换失败也会被静默跳过,导入后要核对行数。
插入后取回自增主键的方式不同:MySQL 用 LAST_INSERT_ID()(应用层通常是接口返回),PostgreSQL 用 INSERT … RETURNING id。

插入实践要点

  • 批量插入控制规模:每批 500 到 1000 行,兼顾速度与事务大小
  • 大表导入可以延后重建二级索引,导完再统一建,避免逐行维护索引
  • 插入前确认表约束:非空、唯一、外键任一不满足都会整行失败
  • 取回自增主键用 RETURNING 或接口返回值,不要用 SELECT MAX(id) 猜
  • 初始化脚本要可重复执行:用 upsert 或先清理再插入,避免重复导入产生脏数据
插入前先定主键策略:自增、UUID、业务编号各有取舍,主键类型与生成方式一旦上线,后续改造成本很高。
插入的列上若有外键约束,父表记录必须先存在,否则整行插入失败;批量导入时要按表之间的依赖顺序安排。

易错点

  • 不写列清单导致插入与表列顺序强绑定,加列后数据写错位置且不易发现
  • 批量插入行数过多撑爆 max_allowed_packet 或生成超大事务,失败后整批回滚
  • INSERT IGNORE 静默吞掉类型转换失败与截断错误,导入结果与源数据不一致
  • 在循环里逐行单条插入,性能比多行 VALUES 差一个数量级
  • 自增列被显式写入较大值,导致后续自增从该值继续,出现编号跳跃

数据来源与参考

  • MySQL 8.0 Reference Manual · INSERT
  • PostgreSQL Documentation · INSERT
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌