insert into 语句需显式指定字段名与值,字符串用单引号,字段数与值数量顺序须严格一致;存在唯一索引时可用on duplicate key update实现“存在则更新”,前提是有primary key或unique约束。

INSERT INTO 语句的基本写法
MySQL 插入单条数据最常用的是 INSERT INTO 语句,核心是明确指定表名、字段名和对应值。不推荐省略字段列表(即不用 INSERT INTO table VALUES (...)),因为一旦表结构变更(比如加了新字段、调整了顺序),这条语句可能报错或写入错误列。
实操建议:
- 始终显式写出字段名,例如:
INSERT INTO users (name, email, created_at) VALUES ('张三', 'zhang@example.com', NOW()) - 字符串值必须用单引号
' '包裹;数字、NOW()、NULL等字面量不加引号 - 字段数与
VALUES中值的数量、顺序必须严格一致 - 如果某字段允许
NULL且不想赋值,显式写NULL,不要留空
处理主键冲突:ON DUPLICATE KEY UPDATE
当表有唯一索引(如 UNIQUE 或主键)时,重复插入会触发 Duplicate entry 错误。若想“存在则更新”,用 ON DUPLICATE KEY UPDATE。
常见错误现象:
直接执行 INSERT INTO ... VALUES (...) ON DUPLICATE KEY UPDATE name=VALUES(name) 却没定义任何唯一约束——该子句完全不生效,也不会报错,容易误以为逻辑已覆盖。
使用前提:
- 表中至少有一个
PRIMARY KEY或UNIQUE索引 -
VALUES(col_name)是引用本次 INSERT 中该列的值,不是变量名 - 只对触发冲突的那行生效,不影响其他行
示例:
INSERT INTO users (id, name, email) VALUES (1001, '李四', 'li@example.com') ON DUPLICATE KEY UPDATE name=VALUES(name), email=VALUES(email);
避免 SQL 注入:优先用预处理语句
拼接字符串构造 INSERT 语句(如 "INSERT INTO ... VALUES ('" + name + "')" )在 Web 或用户输入场景下极危险,会导致 SQL 注入。
为什么这样做:
- 数据库驱动(如 MySQLi、PDO)能将参数与 SQL 结构分离,彻底阻断恶意输入解析为代码
- 自动处理引号、转义、编码问题,比手写
mysqli_real_escape_string()更可靠 - 多数 ORM(如 Laravel Eloquent、Django ORM)底层默认使用预处理
简单示意(PDO):
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute(['王五', 'wang@example.com']);
注意自增主键与返回值
很多业务需要刚插入记录的 ID(比如用于关联子表)。MySQL 提供 LAST_INSERT_ID(),但它的行为依赖连接上下文。
容易踩的坑:
- 在多线程/并发环境下,不能跨连接调用
LAST_INSERT_ID(),它只对当前连接有效 - 如果插入语句带
ON DUPLICATE KEY UPDATE,且实际走的是更新分支,则LAST_INSERT_ID()返回 0(除非显式在 UPDATE 子句中设为某值) - 某些客户端(如 Node.js 的
mysql2)在execute()后直接提供insertId属性,比手动查更安全
复杂点往往不在语法本身,而在字段约束、并发上下文、输入来源这三者的交叉影响上。写完 INSERT,先看表结构里有哪些 NOT NULL、UNIQUE、DEFAULT,再决定要不要写字段列表、要不要加冲突处理、要不要取返回 ID。











