💫《博主主页》:
🔎 CSDN主页__奈斯DB
🔎 IF Club社区主页__奈斯、
🔥《擅长领域》:擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控;并对SQLserver、NoSQL(Redis)有了解
💖如果觉得文章对你有所帮助,欢迎点赞收藏加关注💖
如果你是MySQL用户,想必早已习惯了 AUTO_INCREMENT 带来的便利——只需简单声明,插入数据时完全不用考虑主键值。但在Oracle中,事情就没那么简单了🤔。当MySQL用户在Oracle中尝试同样的操作时,往往会收获一个无情的报错 💥。别担心,Oracle提供了自己的解决方案,虽然稍显复杂,但更加灵活强大 💪!
在Oracle 12c之前的版本中,实现主键自增需要"序列+触发器"的组合拳 👊:
- 1️⃣ 先创建序列作为ID生成器 🏷️
- 2️⃣ 再通过触发器自动填充ID 🤖
这种方式虽然步骤多了些,但能完全模拟MySQL的自动递增效果。当然对于喜欢手动控制的开发者来说,可以直接调用序列的NEXTVAL来获取下一个值🎮,略过创建触发器这步。
好消息是📣,Oracle 12c终于引入了类似于MySQL自增的 IDENTITY列 特性🆕,让主键自增的实现变得简单许多。不过即便是这样,Oracle的 IDENTITY列 在功能和细节上仍与MySQL的AUTO_INCREMENT有所差异 🔄。这种差异恰恰体现了两种数据库不同的设计哲学 🧠:
- MySQL:简单易用 👍
- Oracle:灵活可控 🎛️
无论是选择MySQL的便捷还是Oracle的灵活,了解它们实现主键自增的机制都至关重要 📚。在简单项目和单机环境中,MySQL的 AUTO_INCREMENT 无疑是更优选择 ✅;而在需要更复杂ID生成策略或分布式系统中,Oracle的序列方案则展现出其独特优势 💎。
在Oracle 12c官方文档中可查的的伪列总共有10个,对于网上的博客,以及其他学习资料对伪列的介绍都非常少,几乎没有大佬去讲关于伪列。那么博主将用一个系列去认真介绍一下这10个伪列,对于比较常用的伪列将用独立的一篇文章介绍,对于不常用的伪列将用一篇文章简单介绍清楚其用途即可,因为在实际工作中有几个伪列真的非常有用处,关于伪列的系列文章如下:
- 第一篇:伪列之ORA_ROWSCN:精准查看行数据被修改的最后时间
- 第二篇:伪列之Sequence:利用CURRVAL和NEXTVAL实现主键自增(含 12c 新特性通过 Identity 列实现主键自增) (当前篇)
- 第三篇:伪列之Version Query:数据行变更历史追踪
- 第四篇:伪列之ROWID:快速查找数据行的物理地址
- 第五篇:伪列之ROWNUM:分页查询的实现
- 第六篇:伪列之Hierarchical Query(层次查询)、COLUMN_VALUE(列值提取)、OBJECT_ID(对象标识)、OBJECT_VALUE(对象值访问)、XMLDATA(XML原始数据)
特别说明💥:本篇文章部分理论性知识点均来源于版权归 Oracle 所有的官方公开文档手册,并结合了我个人的解读和案例演示。若需要调整,请联系,会尽快处理😄
官方文档对于CURRVAL、NEXTVAL伪列的介绍(Oracle 12c):
Sequence Pseudocolumns
官方文档对于identity列的介绍(Oracle 12c):
CREATE TABLE
目录
一、序列介绍
1、序列介绍:
序列是一个可以生成唯一顺序值的模式对象。这些值通常用于主键和唯一键。可以在SQL语句中使用以下伪列引用序列值:
CURRVAL: 返回序列的当前值 NEXTVAL: 增加序列并返回下一个值
需要使用序列名称限定CURRVAL和NEXTVAL:
sequence.CURRVAL sequence.NEXTVAL
需要在另一个用户的模式中引用当前或下一个序列值,需要授予该序列的SELECT对象权限或SELECT ANY SEQUENCE系统权限,并且需要使用包含该序列的模式来限定序列:
schema.sequence.CURRVAL schema.sequence.NEXTVAL
要引用远程数据库上序列的值,必须使用完整的或部分数据库链接名称来限定该序列:
schema.sequence.CURRVAL@dblink schema.sequence.NEXTVAL@dblink 注意:一个序列可以被许多用户同时访问,无需等待或锁定。
2、序列值(CURRVAL和NEXTVAL)的适用场景:
- 不在子查询、物化视图或视图中的 SELECT 语句的查询列表
- INSERT 语句中子查询的查询列表
- INSERT 语句的 VALUES 子句
- UPDATE 语句的 SET 子句
3、序列值(CURRVAL和NEXTVAL)的限制:
- DELETE、SELECT 或 UPDATE 语句中的子查询
- 视图或物化视图的查询
- 带有 DISTINCT 操作符的 SELECT 语句
- 带有 GROUP BY、HAVING或 ORDER BY 子句的 SELECT 语句
- 与其他 SELECT 语句通过 UNION、INTERSECT 或 MINUS 集合运算符组合的 SELECT 语句
- SELECT 语句中的 WHERE 子句
- CHECK 约束的条件
- 在CREATE TABLE 或ALTER TABLE 语句中的DEFAULT 表达式
4、序列值(CURRVAL和NEXTVAL)的使用方法:
在创建序列时,可以定义其初始值(initial value)和增量(increment)。首次调用 NEXTVAL 会返回序列的初始值,后续每次调用 NEXTVAL 都会按定义的增量递增序列值,并返回新值。而 CURRVAL 总是返回序列的当前值,即最后一次 NEXTVAL 调用所返回的值。注意:在会话中首次使用 CURRVAL 之前,必须先通过 NEXTVAL 初始化序列。
单条 SQL 语句中的序列递增规则:
在包含NEXTVAL
的 SQL 语句中,Oracle 仅对序列递增 一次 ,具体取决于以下情况:
- SELECT 语句(每行递增一次)
- 在SELECT中查找序列的下一个值。示例:
SELECT employees_seq.nextval FROM DUAL;
- INSERT … SELECT(单表或多表插入):对于多表插入(multitable insert),NEXTVAL 必须出现在 VALUES 子句中,即使它在多个插入分支中被引用,序列也仅对子查询返回的每一行递增一次。
- CREATE TABLE … AS SELECT
- CREATE MATERIALIZED VIEW … AS SELECT
- UPDATE 语句(每更新一行递增一次)
- 带 VALUES 子句的 INSERT 语句(每插入一行递增一次)。示例:
INSERT INTO employees VALUES (employees_seq.nextval, 'John', 'Doe', 'jdoe', '555-1212', TO_DATE(SYSDATE), 'PU_CLERK', 2500, null, null, 30);
- 多表插入(INSERT ALL / INSERT FIRST)
- 多表插入被视为 单条 SQL 语句,因此 NEXTVAL 仅对 SELECT 部分返回的每一行递增一次。
- 如果在 INSERT ALL / FIRST 的任何部分多次引用 NEXTVAL,则所有插入分支将使用相同的序列值,即使某行可能被插入多次。
- MERGE 语句(每合并一行递增一次)
- NEXTVAL 可出现在 merge_insert_clause(插入子句)或 merge_update_clause(更新子句)中,或同时出现。
- 即使序列值未实际用于更新或插入操作,NEXTVAL 仍会对
每一行更新或插入
递增。- 如果在这些子句中多次引用 NEXTVAL,则序列仅递增一次,并为该行的所有
NEXTVAL
返回相同值。- 多表插入(INSERT ALL)的输入行
- NEXTVAL 对子查询返回的每一行仅递增一次,无论该行被映射到多少个插入目标表。
重复引用 NEXTVAL 或 CURRVAL 的规则:
- 如果上述场景中
多次引用 NEXTVAL
,Oracle 仅递增序列一次,并返回相同的值。- 如果同时引用
CURRVAL 和 NEXTVAL
,Oracle 会递增序列,并返回相同的值给两者。示例:INSERT INTO orders (order_id, order_date, customer_id) VALUES (orders_seq.nextval, TO_DATE(SYSDATE), 106); INSERT INTO order_items (order_id, line_item_id, product_id) VALUES (orders_seq.currval, 1, 2359); INSERT INTO order_items (order_id, line_item_id, product_id) VALUES (orders_seq.currval, 2, 3290); INSERT INTO order_items (order_id, line_item_id, product_id) VALUES (orders_seq.currval, 3, 2381);
二、实现主键的自动生成
在Oracle数据库中,不像MySQL或SQL Server有直接的AUTO_INCREMENT属性,可以通过如下如下几种方式实现主键自增功能:
方法 优点 缺点 序列+触发器 完全自动化,最接近自增 需要维护触发器 仅用序列 简单直接 需要手动或应用控制 IDENTITY列 语法简洁 仅12c以上版本支持 GUID/UUID 全局唯一,适合分布式 占用空间大,无序 最佳实践建议:
1. 对于Oracle 12c以下版本,推荐使用"序列+触发器"组合
2. 对于Oracle 12c及以上版本,可以使用IDENTITY列简化操作
3. 在分布式系统中,考虑使用GUID/UUID避免主键冲突
4. 序列可以设置CACHE提高性能,但可能造成序列号不连续
注意:Oracle的序列不保证绝对连续(特别是使用CACHE时),但在大多数业务场景中这不影响使用。下文主要详细介绍全自动方式(序列+触发器)、半自动方式(手动调用序列)、IDENTITY列方式,
关于GUID/UUID方式在典型的集中式Oracle数据库环境中,不建议常规使用GUID/UUID作为主键,因为不需要GUID的分布式唯一特性
,不过简单写个使用GUID/UUID作为主键的表结构,有所了解即可:CREATE TABLE table_name ( id RAW(16) DEFAULT SYS_GUID(), name VARCHAR2(50), PRIMARY KEY (id) );
2.1 序列方式:包含全自动方式(序列+触发器) 和 半自动方式(手动调用序列)(Oracle 12c以下的版本)
序列是一种数据库对象,可供多用户生成唯一的整数值,常用于自动生成主键值。
用途说明:
- 独立于事务的递增值
- 序列号生成后,即使事务回滚(rollback),序列仍会保持递增。
- 如果多个用户并发递增同一序列,每个用户获取的序列号可能存在间隔(gaps),因为其他用户也在生成序列号。
用户无法获取其他用户生成的序列值
。一旦序列值被某用户生成,该用户可重复访问该值(通过 CURRVAL
),即使其他用户已递增序列。- 与表解耦
- 序列独立于表存在,因此
同一序列可服务于一个或多个表
。- 某些序列号可能看似“跳过”,因为它们已在回滚的事务中被生成并使用。
- 单个用户可能无法察觉其他用户正在使用同一序列。
- 访问序列值
- 创建序列后,可通过以下伪列在 SQL 语句中访问其值:
CURRVAL:
返回序列的当前值(需在同一会话中先调用NEXTVAL
初始化)。NEXTVAL:
递增序列并返回新值。
一、创建序列(create sequence)
创建序列的语法:
CREATE SEQUENCE [ schema. ] sequence [ SHARING = { METADATA | DATA | NONE } ] [ { INCREMENT BY | START WITH } integer | { MAXVALUE integer | NOMAXVALUE } | { MINVALUE integer | NOMINVALUE } | { CYCLE | NOCYCLE } | { CACHE integer | NOCACHE } | { ORDER | NOORDER } | { KEEP | NOKEEP } | { SESSION | GLOBAL } ]...;
参数 含义 默认值 INCREMENT BY 序列的步长(增量),可为正数(递增)或负数(递减)。 未指定 INCREMENT BY 时,默认递增步长为 1。 START WITH 序列的初始值。 1(递增)或-1(递减) MAXVALUE integer | NOMAXVALUE
MINVALUE integer | NOMINVALUEMAXVALUE:序列的最大值。若为 NOMAXVALUE,递增序列上限为 10^27,递减为 -1。
MINVALUE:序列的最小值。若为 NOMINVALUE,递减序列下限为 -10^26,递增为 1。
若同时省略 MAXVALUE 和 MINVALUE,默认允许的最大值/最小值由步长方向决定。NOMAXVALUE
NOMINVALUECYCLE | NOCYCLE 序列达到极值后是否循环(CYCLE:循环,NOCYCLE:停止)。
若启用 CYCLE,序列达到 MAXVALUE 后会从 MINVALUE 重新开始(反之亦然)。NOCYCLE CACHE integer | NOCACHE 预分配的序列值数量(提升性能),NOCACHE表示不缓存。
CACHE 参数可减少磁盘 I/O,但数据库崩溃时可能导致缓存中的序列值丢失(产生间隔)。如果省略CACHE和NOACHE,则数据库默认缓存20个序列号。 ORDER | NOORDER 确保序列值按请求顺序生成(ORDER),或仅保证唯一性(NOORDER)。
ORDER 适用于 RAC(实时应用集群),但可能降低性能。NOORDER SESSION | GLOBAL 序列仅在当前会话中有效(GLOBAL表示跨会话共享)。 GLOBAL 相关视图(查看序列使用情况):
select * from all_sequences; ###查看当前用户下有权限访问所有的序列信息 select * from user_sequences: ###查看的是当前用户下序列的信息 select * from dba_sequences: ###查看的是实例下所以的序列的信息 sequence_name:序列名 Min_value:最小值 Max_value:最大值 Increnent_by:增量数 cycle_flag(C):序列生成器的值达到限制值后是否循环,默认N Last_number:下一个数值(代表sequenca_name.nexval)
案例:通过 全自动方式(序列+触发器) 和 半自动方式(手动调用序列) 实现主键自动生成
特性 全自动方式(序列+触发器) 半自动方式(手动调用序列) 实现复杂度 需要创建触发器 只需创建序列 使用便利性 插入时无需考虑ID 每次插入需显式调用序列 灵活性 较低,所有插入必须使用相同规则 较高,可灵活控制何时使用序列 适用场景 简单的自增主键需求 需要更复杂ID生成逻辑的场景 性能影响 触发器有轻微性能开销 无额外开销 全自动方式:序列+触发器
1)创建测试表
CREATE TABLE liu_oracleoltp_employees ( emp_id NUMBER PRIMARY KEY, emp_name VARCHAR2(100), hire_date DATE, salary NUMBER );
2)创建序列(从1开始,增量为1,无最大最小值,不循环,默认缓存)
CREATE SEQUENCE liu_oracleoltp_emp_seq START WITH 1 INCREMENT BY 1 NOMAXVALUE NOMINVALUE NOCYCLE; select * from user_sequences where sequence_name='LIU_ORACLEOLTP_EMP_SEQ'; ###查看的是当前用户下序列的信息
3)创建触发器
CREATE OR REPLACE TRIGGER liu_oracleoltp_emp_auto_id BEFORE INSERT ON liu_oracleoltp_employees FOR EACH ROW BEGIN -- 在插入前自动获取下一个序列值赋给emp_id SELECT liu_oracleoltp_emp_seq.NEXTVAL INTO :new.emp_id FROM dual; END; /
4)测试全自动方式
-- 插入数据时不需要指定emp_id INSERT INTO liu_oracleoltp_employees (emp_name, hire_date, salary) VALUES ('张三', SYSDATE, 5000); INSERT INTO liu_oracleoltp_employees (emp_name, hire_date, salary) VALUES ('李四', SYSDATE, 6000); -- 查询结果 SELECT * FROM liu_oracleoltp_employees;
半自动方式:手动调用序列
1)创建测试表
CREATE TABLE liu_oracleoltp_orders ( order_id NUMBER PRIMARY KEY, customer_id NUMBER, order_date DATE, amount NUMBER );
2)创建序列(从1开始,增量为1,无最大最小值,不循环,默认缓存)
CREATE SEQUENCE liu_oracleoltp_order_seq START WITH 1 INCREMENT BY 1 NOMAXVALUE NOMINVALUE NOCYCLE; select * from user_sequences where sequence_name='LIU_ORACLEOLTP_ORDER_SEQ'; ###查看的是当前用户下序列的信息
3)手动调用序列插入数据
– 方式1:在INSERT语句中直接引用序列(通过currval(当前)和nextval(下一个)两个伪列实现)INSERT INTO liu_oracleoltp_orders (order_id, customer_id, order_date, amount) VALUES (liu_oracleoltp_order_seq.NEXTVAL, 101, SYSDATE, 199.99); INSERT INTO liu_oracleoltp_orders (order_id, customer_id, order_date, amount) VALUES (liu_oracleoltp_order_seq.NEXTVAL, 102, SYSDATE, 201.11); -- 查询当前序列值 SELECT liu_oracleoltp_order_seq.CURRVAL FROM dual;
-- 查询结果 SELECT * FROM liu_oracleoltp_orders;
– 方式2:先获取序列值再插入
DECLARE v_next_order_id NUMBER; BEGIN -- 先获取下一个序列值 SELECT liu_oracleoltp_order_seq.NEXTVAL INTO v_next_order_id FROM dual; -- 使用获取的值插入数据 INSERT INTO liu_oracleoltp_orders (order_id, customer_id, order_date, amount) VALUES (v_next_order_id, 102, SYSDATE, 299.99); COMMIT; END; / -- 查询当前序列值 SELECT liu_oracleoltp_order_seq.CURRVAL FROM dual;
-- 查询结果 SELECT * FROM liu_oracleoltp_orders;
4)序列的注意事项:select liu_oracleoltp_order_seq.currval from dual; select liu_oracleoltp_order_seq.nextval from dual;
- CURRVAL 总是返回当前SEQUENCE的值,但是在第一次NEXTVAL初始化之后才能使用CURRVAL,否则会出错。
- 第一次NEXTVAL返回的是初始值;随后的NEXTVAL会自动增加你定义的INCREMENT BY值,然后返回增加后的值。一次NEXTVAL会增加SEQUENCE的值,所以如果你在同一个语句里面使用多个NEXTVAL,其值就是不一样的。
- 在序列中设置了cycle(循环)时,当sequence的值达到maxvalue(最大值)后会从minvalue(最小值)开始循环(minvalue在不设置时默认为1)。
- 创建序列后,不能使用currval直接插入当前值,必须使用nextval先取值才能使用。否则报ora-08002:当前值尚未在此进程中定义。
二、修改序列(alter sequence)
修改序列的语法:
ALTER SEQUENCE [ schema. ] sequence { INCREMENT BY integer | { MAXVALUE integer | NOMAXVALUE } | { MINVALUE integer | NOMINVALUE } | { CYCLE | NOCYCLE } | { CACHE integer | NOCACHE } | { ORDER | NOORDER } | { KEEP | NOKEEP } | { SESSION | GLOBAL } } ...;
参数 说明 INCREMENT BY increment 修改序列的增量值(可为正负整数) MAXVALUE integer | NOMAXVALUE MAXVALUE integer:设置序列的最大值
NOMAXVALUE:指定序列没有最大值限制(默认值)MINVALUE integer | NOMINVALUE MINVALUE integer:设置序列的最小值
NOMINVALUE:指定序列没有最小值限制(默认值)CYCLE | NOCYCLE CYCLE:允许序列在达到极值后循环
NOCYCLE:禁止序列循环(默认值)CACHE integer | NOCACHE CACHE integer:指定预分配的序列值数量(性能优化)
NOCACHE:禁用序列值缓存ORDER | NOORDER ORDER:确保序列值按请求顺序生成(RAC环境)
NOORDER:不保证序列值顺序(默认值)SESSION | GLOBAL SESSION:序列仅在当前会话中有效
GLOBAL:序列在所有会话中有效(默认值)
案例:修改现有序列的开始数值
重置起始数值的方式:失败
SQL> alter sequence liu_oracleoltp_order_seq start with 1; ---对于启动的序列不能通过指定起始数值来进行重置为1,报错ORA-02283: 无法变更启动序列号
修改序列的增加步长:成功(也适用于本来INCREMENT BY不为1的增加)
- 情况一:回退的值比现在的值大(如:5回退到18,18为current值)
select * from user_sequences WHERE SEQUENCE_NAME='序列名'; ---记录LAST_NUMBER的值 select 序列名.currval from dual; alter sequence 序列名 increment by 需要回退到那个值-序列名.currval; select 序列名.nextval from dual; alter sequence 序列名 increment by 1;
- 情况二:回退的值比现在的值小(如:13回退到5,5为current值)
select * from user_sequences WHERE SEQUENCE_NAME='序列名'; ---记录LAST_NUMBER的值 select 序列名.currval from dual; alter sequence 序列名 increment by -(序列名.currval-需要回退到那个值); select 序列名.nextval from dual; alter sequence 序列名 increment by 1;
三、删除序列(drop sequence)
修改序列的语法:
DROP SEQUENCE [ schema. ] sequence_name ; ---删除序列的人应该是序列的创建者或拥有DROP ANY SEQUENCE系统权限的用户
🎉 章节过渡:解锁Oracle 12c的新姿势!
✨ 前情提要: 已经掌握了Oracle传统版的自增主键方案——
- 全自动的「序列+触发器」组合拳 🤖💥
- 半自动的「手动调用序列」DIY玩法 🔧🎯
📣 那么在Oracle 12c版本中,带来了非常方便的 IDENTITY列 特性,可以像MySQL一样潇洒地实现主键自增~
👇 下一站:「如何用IDENTITY列优雅搞定主键自增」🚀
2.2 identity列方式(Oracle 12c以上的版本)
identity列是Oracle 12c引入的特性,用于自动生成唯一的数值,通常用作主键。其行为类似于其他数据库的AUTO_INCREMENT。
经过测试,直接在创建表时指定identity列,就可以实现主键自动生成,但其本质上还是会创建一个序列,只不过序列名是Oracle自动命名的,详细过程参考下面的案例。
与序列(SEQUENCE)的对比:
特性 Identity列 传统序列 依赖对象 依赖对象 独立数据库对象 作用范围 仅限当前表 可跨多表共享 事务回滚 丢失的值不会回收 同左 RAC支持 自动处理 需显式设置ORDER/NOORDER 维护复杂度 无需额外对象(序列/触发器) 需要维护序列和触发器 语法:create table语法中的一部分
column_name NUMBER GENERATED [ ALWAYS | BY DEFAULT [ ON NULL ] ] AS IDENTITY [ ( identity_options ) ]
参数 作用 GENERATED ALWAYS 指定 ALWAYS 时,Oracle 数据库始终使用序列生成器为该列赋值。如果尝试通过 INSERT 或 UPDATE 显式指定该列的值,系统将返回错误(ORA-32795)。没有指定时,这是一个默认值 GENERATED BY DEFAULT 指定 BY DEFAULT 时,Oracle 默认使用序列生成器赋值,但也允许显式指定列值。 GENERATED BY DEFAULT ON NULL 如果同时指定 ON NULL,则在后续 INSERT 语句尝试插入 NULL 时,系统会自动使用序列生成器赋值。 identity_options
语法如下:
{ START WITH ( integer | LIMIT VALUE )
| INCREMENT BY integer
| ( MAXVALUE integer | NOMAXVALUE )
| ( MINVALUE integer | NOMINVALUE )
| ( CYCLE | NOCYCLE )
| ( CACHE integer | NOCACHE )
| ( ORDER | NOORDER ) }...用于配置序列生成器,其参数与 CREATE SEQUENCE 语句相同(如 START WITH、INCREMENT BY 等)。
例外情况:START WITH LIMIT VALUE 是 identity_options 特有的参数,仅可在 ALTER TABLE MODIFY 中使用。
注意:创建标识列时,Oracle 建议将 CACHE 值设为大于默认值 20,以提高性能。使用限制:
- 数量限制:每张表只能有一个Identity标识列。
- 数据类型限制:必须为数值类型(如
NUMBER、INTEGER
),不能是用户自定义类型。- 默认值冲突:不能同时在列定义中指定
DEFAULT
子句。- 隐式约束:系统会隐式添加
NOT NULL
和NOT DEFERRABLE
约束。若显式定义与之冲突的约束(如 NULL),将报错。- 加密限制:若标识列被加密,加密算法可能被推断。Oracle 建议对标识列使用强加密算法。
- 继承限制:通过
CREATE TABLE AS SELECT
创建的表不会继承原列的标识属性。
数据字典视图:
SELECT * FROM USER_TAB_IDENTITY_COLS; — 查看所有Identity列
案例:通过 Identity列方式 实现主键自动生成
选项 ALWAYS BY DEFAULT BY DEFAULT ON NULL 自动生成值 始终 仅当未显式指定值时 当显式指定 NULL 或未提供值时 允许手动赋值 禁止(报错) 允许 允许(除非显式插入 NULL ) 基础Identity列:
1)创建带Identity列的表
CREATE TABLE liu_oracleoltp_employees ( emp_id NUMBER GENERATED ALWAYS AS IDENTITY, -- 完全自动生成 emp_name VARCHAR2(100) NOT NULL, hire_date DATE DEFAULT SYSDATE, salary NUMBER(10,2), CONSTRAINT pk_emp PRIMARY KEY (emp_id) );
2)插入数据(无需指定emp_id)
INSERT INTO liu_oracleoltp_employees (emp_name, salary) VALUES ('张三', 8500); INSERT INTO liu_oracleoltp_employees (emp_name, salary) VALUES ('李四', 9200);
注意:如果IDENTITY列指定为ALWAYS参数时,如果尝试手动指定ID,会报错,因为Oracle 数据库始终使用序列生成器为该列赋值。如果尝试通过 INSERT 或 UPDATE 显式指定该列的值,系统将返回错误(ORA-32795)。如下图:
3)查询结果
SELECT * FROM liu_oracleoltp_employees;
SELECT * FROM USER_TAB_IDENTITY_COLS where table_name='LIU_ORACLEOLTP_EMPLOYEES'; ###通过视图查看表的Identity列信息
select * from user_sequences where sequence_name='ISEQ$$_125459';
###查看的是当前用户下序列的信息。identity列方式实现主键自动生成本质上还是会创建一个序列,只不过序列名是Oracle自动命名的
自定义Identity列属性:
1)创建带Identity列的表
CREATE TABLE liu_oracleoltp_departments ( dept_id NUMBER GENERATED ALWAYS AS IDENTITY ( START WITH 100 -- 从100开始 INCREMENT BY 10 -- 每次增加10 MAXVALUE 9999 -- 最大值9999 NOCYCLE -- 不循环 CACHE 30 -- 缓存30个值 ), dept_name VARCHAR2(50) NOT NULL, location VARCHAR2(100), CONSTRAINT pk_dept PRIMARY KEY (dept_id) );
2)插入数据
BEGIN FOR i IN 1..5 LOOP INSERT INTO liu_oracleoltp_departments (dept_name, location) VALUES ('部门'||i, '位置'||i); END LOOP; COMMIT; END; /
注意:如果IDENTITY列指定为ALWAYS参数时,如果尝试手动指定ID,会报错,因为Oracle 数据库始终使用序列生成器为该列赋值。如果尝试通过 INSERT 或 UPDATE 显式指定该列的值,系统将返回错误(ORA-32795)。如下图:
3)查询结果
SELECT * FROM liu_oracleoltp_departments;
SELECT * FROM USER_TAB_IDENTITY_COLS where table_name='LIU_ORACLEOLTP_DEPARTMENTS'; ###通过视图查看表的Identity列信息
select * from user_sequences where sequence_name='ISEQ$$_125462';
###查看的是当前用户下序列的信息。identity列方式实现主键自动生成本质上还是会创建一个序列,只不过序列名是Oracle自动命名的
BY DEFAULT模式(允许手动指定值):
1)创建带Identity列的表
CREATE TABLE liu_oracleoltp_projects ( project_id NUMBER GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 INCREMENT BY 1 ), project_name VARCHAR2(100) NOT NULL, start_date DATE, CONSTRAINT pk_project PRIMARY KEY (project_id) );
2)自动生成ID
INSERT INTO liu_oracleoltp_projects (project_name, start_date) VALUES ('OA系统升级', DATE '2023-09-01');
3)手动指定ID:IDENTITY列指定为 BY DEFAULT 参数时,Oracle 默认使用序列生成器赋值,但也允许显式指定列值。
INSERT INTO liu_oracleoltp_projects (project_id, project_name, start_date) VALUES (100,'特殊项目', DATE '2025-09-01');
4)查询结果
SELECT * FROM liu_oracleoltp_projects;
SELECT * FROM USER_TAB_IDENTITY_COLS where table_name='LIU_ORACLEOLTP_PROJECTS'; ###通过视图查看表的Identity列信息
select * from user_sequences where sequence_name='ISEQ$$_125465';
###查看的是当前用户下序列的信息。identity列方式实现主键自动生成本质上还是会创建一个序列,只不过序列名是Oracle自动命名的
经过前面的探索,我们已经掌握了Oracle中实现主键自增的三大法宝:
1️⃣ 传统Oracle版: 序列+触发器 = 自动挡老司机 🚗💨
2️⃣ 手动控制版: 直接调序列 = 手动挡玩操控 🏎️✨
3️⃣ 12c新技能: IDENTITY列 = 智能自动驾驶 🤖🌟
选择建议:如果是维护老项目,成熟的"序列+触发器"方案最为稳妥;新建系统且版本允许的话,IDENTITY列无疑是最优雅的选择;至于GUID方案,虽然它在分布式环境中表现出色,但在集中式Oracle架构中反而会带来性能和维护上的负担,建议谨慎采用。
记住这个技术选型口诀:“老项目用序列,新系统选IDENTITY,分布式考虑GUID”。希望这篇指南能帮助您在Oracle主键设计的道路上少走弯路!如果觉得有用,欢迎点赞收藏,我们下期技术分享再见!🚀