oracle 12c+ 支持 generated by default as identity 实现原生自增主键,无需序列和触发器;11g及以前须用 sequence + trigger 组合模拟,且需注意大小写、起始值及触发器条件。
oracle 表本身不支持像 mysql 那样直接声明 auto_increment,navicat 也不能“一键勾选”主键自增。你必须显式创建序列(sequence)和触发器(trigger),才能实现插入时自动填充主键值。
创建序列时要注意 schema 和命名规范
Oracle 对大小写敏感,尤其在 Navicat 中用图形界面建序列时,默认生成的名称是大写;但如果你建表时用了小写字段名(比如 "id"),后续触发器里引用就必须加双引号,否则会报 ORA-00904: invalid identifier。
- 序列名建议全大写、无特殊字符,例如
SEQ_USER_ID,避免后期 SQL 引用出错 - 如果表属于非当前用户 schema(比如
TEST用户建的表,但你在ADMIN下操作),创建序列时要显式带上 schema:CREATE SEQUENCE TEST.SEQ_USER_ID ... -
NOCACHE更安全——缓存(CACHE 20)能提升性能,但数据库异常关闭可能导致序列号跳号(如从 100 直接跳到 120) -
START WITH值需大于当前表中最大主键值,否则插入可能违反唯一约束
触发器必须绑定 INSERT BEFORE 且正确引用 :NEW
触发器核心是拦截每次 INSERT,把序列下一个值赋给主键字段。关键点在于语法结构和字段名大小写匹配。
- 触发器类型必须是
BEFORE INSERT,不能是AFTER—— 否则主键已提交,再改会报错 - 触发器体里必须用
:NEW."id"(带双引号)或:NEW.id(不带引号),取决于你建表时是否用双引号定义了字段名 - 务必加上
WHEN (:NEW.id IS NULL)条件,否则手动指定主键时会被覆盖,导致数据错乱 - Navicat 图形化建触发器时,“触发时机”选“插入前”,“触发事件”选“每行”,并勾选“启用”
插入数据时不显式传主键值才生效
序列+触发器方案只在你不提供主键值时起作用。一旦你在 INSERT 语句里写了主键列,触发器仍会执行,但 :NEW.id 已被赋值,SELECT ... INTO :NEW.id 实际无效(除非你没加 WHEN 条件,那就会强行覆盖)。
- ✅ 正确写法:
INSERT INTO users (name, email) VALUES ('Alice', 'a@example.com'); - ❌ 错误写法:
INSERT INTO users (id, name, email) VALUES (1, 'Alice', 'a@example.com');—— 这条会成功,但触发器没参与,且若 id 冲突会直接报ORA-00001 - ⚠️ 注意 Navicat「快速插入」弹窗默认会显示所有字段(含主键),容易误填。建议关掉该功能,或插入前手动删掉
id行
Oracle 12c+ 可用 IDENTITY 列替代序列+触发器
如果你用的是 Oracle 12c 或更高版本(如 19c、21c),根本不用序列和触发器——直接在建表时用 GENERATED BY DEFAULT AS IDENTITY。
- 建表示例:
CREATE TABLE users (id NUMBER GENERATED BY DEFAULT AS IDENTITY, name VARCHAR2(50)); - Navicat 设计表时,在字段属性里找 “Identity” 或 “Auto Increment” 开关(部分版本支持),但更稳妥的方式仍是手写 DDL
- 该方式原生支持
ON NULL、START WITH、INCREMENT BY等参数,且无需维护额外对象 - 旧表无法直接修改为 identity 列,需重建表或用
ALTER TABLE ... MODIFY id GENERATED ...(12.1+ 支持)
真正容易被忽略的是:Navicat 的图形操作看似简化流程,但它不会自动帮你校验序列起始值是否大于现有数据最大值,也不会提醒你触发器里字段名大小写是否匹配。这些细节一错,插入就报错,而错误信息往往只说“PL/SQL: ORA-00904”,不指明哪一行哪一列——得自己翻 DDL 和表结构反复比对。











