文章
关于自增id主键插入0的问题
目录
不同数据库对 “在自增(Auto‑Increment/IDENTITY/序列)主键列上插入 0” 的处理方式是不一样的,下面用中文分别说明几种常见引擎的行为:#
SQLite#
- 表定义举例:
CREATE TABLE t ( id INTEGER PRIMARY KEY AUTOINCREMENT, ... ); ```
- 行为
如果你写:
INSERT INTO t(id, ...) VALUES (0, ...);
INSERT INTO t(id, ...) VALUES (NULL, ...);
```
SQLite 会把 0 或 NULL 当作“请自动分配下一个 rowid”,插入时会忽略你给的 0,改用序列中下一个可用值。
- 非零值
如果你显式插入一个非零的
id(比如INSERT … VALUES(42, …)),SQLite 会直接使用 42(前提是不与已有 rowid 冲突)。
MySQL / MariaDB#
- 表定义举例:
CREATE TABLE t ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, ... ) ENGINE=InnoDB; ```
- 行为
MySQL 也把
0或NULL视为“请求自增”:
INSERT INTO t(id, ...) VALUES (0, ...); INSERT INTO t(id, ...) VALUES (NULL, ...); ``` 这两种写法都会触发自增,分配下一个自增值。
- 显式值 只要你插入的值非零(且不冲突),MySQL 会按你给的数字插入,并不会跳过或动用序列。
PostgreSQL#
- 表定义举例(
SERIAL或GENERATED):
CREATE TABLE t ( id SERIAL PRIMARY KEY, ... ); ```
- 行为
在 PostgreSQL 里,你向
SERIAL(本质是序列)列插入0,就会真的把0存进去——不会触发序列。 只有这样写才会用序列:
INSERT INTO t DEFAULT VALUES; -- 或者 INSERT INTO t(id, ...) VALUES (DEFAULT, ...); ```#
SQL Server#
- 表定义举例:
CREATE TABLE t ( id INT IDENTITY(1,1) PRIMARY KEY, ... ); ```
- 行为
默认情况下你不能向
IDENTITY列插入任何值(包括 0),会报错。 如果你临时执行:
SET IDENTITY_INSERT t ON;
```
然后再插入,才可以像普通列那样插入 0 或其他数字;这些手动插入的值不会改变下一次自增的起点。#
小结#
| 引擎 | 插入 0 或 NULL | 插入非零值 | 触发自增逻辑 |
|---|---|---|---|
| SQLite | 是(分配下一个) | 是(按值插入) | 0/NULL 自动,省略字段其他手工 |
| MySQL | 是(分配下一个) | 是(按值插入) | 同 SQLite |
| PostgreSQL | 否(插入 0) | 是 | 只省略字段或 DEFAULT 时 |
| SQL Server | 报错(除非开启 IDENTITY_INSERT) | 同上 | 只能通过省略字段触发 |
最佳实践:如果想让列使用自增,通常 不要 显式插入 id,直接省略该列或写成 DEFAULT,让数据库自己分配下一个值。