INSERT不写列名时须严格按表定义顺序提供全部非空字段值;指定列名更安全,支持跳过自增/默认字段;批量插入建议单次≤1000行;INSERT IGNORE与ON DUPLICATE KEY UPDATE行为差异大,需谨慎选择。

INSERT 不写列名时,必须按表定义顺序提供全部非空字段值
MySQL 允许省略列名直接插入,但前提是 VALUES 中的值顺序、数量、类型必须严格匹配表结构(尤其是 NOT NULL 字段和没有默认值的字段)。否则会报错 Column 'xxx' cannot be null 或 Field 'xxx' doesn't have a default value。
- 适用于建表后快速填充测试数据,或表结构极简单且稳定不变的场景
- 一旦表新增了
NOT NULL字段(比如加了created_at TIMESTAMP NOT NULL),原有不带列名的INSERT语句立刻失效 - 值顺序容易和表字段顺序脱节——用
DESCRIBE table_name确认当前顺序,别依赖记忆或旧文档 - 示例:
INSERT INTO users VALUES (1, 'alice', 'alice@example.com');—— 要求users表前三列恰好是id,name,email,且都允许为空或有默认值
INSERT 指定列名能规避字段顺序和缺失风险
显式列出列名是最稳妥的做法,尤其在生产环境。MySQL 只校验所列字段的约束和类型,其余字段按默认值或 NULL 处理(前提是允许)。
- 新增字段不影响旧 SQL,只要新字段有默认值或允许
NULL - 可跳过自增主键(如
id)、时间戳(如created_at)等由数据库自动填充的字段 - 注意:如果列名拼错,错误信息是
Unknown column 'xxx' in 'field list',不是语法错误,容易漏看 - 示例:
INSERT INTO users (name, email) VALUES ('bob', 'bob@example.com');——id和created_at会走默认行为
批量插入多行时,指定列名 + 多值元组效率更高
用单条 INSERT 插入多行,比循环执行多条单行 INSERT 快数倍。但列名只需写一次,VALUES 后跟多个括号元组。
- 每行元组内值顺序必须与前面列名顺序一致,不能混用位置
- MySQL 默认有
max_allowed_packet限制,超长批量可能报错Packets larger than max_allowed_packet are not allowed - 建议单次不超过 1000 行;若需插更多,拆成多个批次,避免锁表时间过长
- 示例:
INSERT INTO users (name, email) VALUES ('carol','c@example.com'), ('dave','d@example.com');
INSERT IGNORE / ON DUPLICATE KEY UPDATE 的实际取舍
遇到主键或唯一索引冲突时,INSERT IGNORE 直接跳过,而 ON DUPLICATE KEY UPDATE 可更新已有记录。二者行为差异大,选错会导致数据静默丢失或误覆盖。
-
INSERT IGNORE不报错但也不告诉你跳了多少行——检查返回的affected_rows值才能确认是否真插入成功 -
ON DUPLICATE KEY UPDATE中的更新表达式不能引用原值做条件判断(比如不能写updated_at = IF(updated_at ),MySQL 8.0+ 才支持 <code>VALUES(col)引用待插入值 - 如果业务逻辑要求“存在则更新时间戳,不存在才新建”,优先用
ON DUPLICATE KEY UPDATE;如果只是防重复且不关心是否跳过,IGNORE更轻量 - 示例:
INSERT INTO users (id, name, email) VALUES (1, 'eve', 'e@example.com') ON DUPLICATE KEY UPDATE name=VALUES(name), email=VALUES(email);
sql_mode 设置——比如开启 STRICT_TRANS_TABLES 后,插入空字符串到 NOT NULL 的 VARCHAR 字段会报错,而关闭时可能转成 NULL 或截断,行为不一致。










