【Oracle篇】伪列之Sequence:利用CURRVAL和NEXTVAL实现主键自增(含 12c 新特性通过 Identity 列实现主键自增)(第二篇,总共六篇)

💫《博主主页》:
   🔎 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)的适用场景:
  1. 不在子查询、物化视图或视图中的 SELECT 语句的查询列表
  2. INSERT 语句中子查询的查询列表
  3. INSERT 语句的 VALUES 子句
  4. UPDATE 语句的 SET 子句
       
3、序列值(CURRVAL和NEXTVAL)的限制:
  1. DELETE、SELECT 或 UPDATE 语句中的子查询
  2. 视图或物化视图的查询
  3. 带有 DISTINCT 操作符的 SELECT 语句
  4. 带有 GROUP BY、HAVING或 ORDER BY 子句的 SELECT 语句
  5. 与其他 SELECT 语句通过 UNION、INTERSECT 或 MINUS 集合运算符组合的 SELECT 语句
  6. SELECT 语句中的 WHERE 子句
  7. CHECK 约束的条件
  8. 在CREATE TABLE 或ALTER TABLE 语句中的DEFAULT 表达式
       
4、序列值(CURRVAL和NEXTVAL)的使用方法:

    在创建序列时,可以定义其初始值(initial value)和增量(increment)。首次调用 NEXTVAL 会返回序列的初始值,后续每次调用 NEXTVAL 都会按定义的增量递增序列值,并返回新值。而 CURRVAL 总是返回序列的当前值,即最后一次 NEXTVAL 调用所返回的值。注意:在会话中首次使用 CURRVAL 之前,必须先通过 NEXTVAL 初始化序列。
   

单条 SQL 语句中的序列递增规则:
    在包含NEXTVAL的 SQL 语句中,Oracle 仅对序列递增 一次 ,具体取决于以下情况:

  1. SELECT 语句(每行递增一次)
    • 在SELECT中查找序列的下一个值。示例:SELECT employees_seq.nextval FROM DUAL;
    • INSERT … SELECT(单表或多表插入):对于多表插入(multitable insert),NEXTVAL 必须出现在 VALUES 子句中,即使它在多个插入分支中被引用,序列也仅对子查询返回的每一行递增一次。
    • CREATE TABLE … AS SELECT
    • CREATE MATERIALIZED VIEW … AS SELECT
  2. UPDATE 语句(每更新一行递增一次)
  3. 带 VALUES 子句的 INSERT 语句(每插入一行递增一次)。示例: INSERT INTO employees VALUES (employees_seq.nextval, 'John', 'Doe', 'jdoe', '555-1212', TO_DATE(SYSDATE), 'PU_CLERK', 2500, null, null, 30);
  4. 多表插入(INSERT ALL / INSERT FIRST)
    • 多表插入被视为 单条 SQL 语句,因此 NEXTVAL 仅对 SELECT 部分返回的每一行递增一次。
    • 如果在 INSERT ALL / FIRST 的任何部分多次引用 NEXTVAL,则所有插入分支将使用相同的序列值,即使某行可能被插入多次。
  5. MERGE 语句(每合并一行递增一次)
    • NEXTVAL 可出现在 merge_insert_clause(插入子句)或 merge_update_clause(更新子句)中,或同时出现。
    • 即使序列值未实际用于更新或插入操作,NEXTVAL 仍会对每一行更新或插入递增。
    • 如果在这些子句中多次引用 NEXTVAL,则序列仅递增一次,并为该行的所有NEXTVAL返回相同值。
  6. 多表插入(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以下的版本)

    序列是一种数据库对象,可供多用户生成唯一的整数值,常用于自动生成主键值。
   
用途说明:

  1. 独立于事务的递增值
    • 序列号生成后,即使事务回滚(rollback),序列仍会保持递增。
    • 如果多个用户并发递增同一序列,每个用户获取的序列号可能存在间隔(gaps),因为其他用户也在生成序列号。
    • 用户无法获取其他用户生成的序列值。一旦序列值被某用户生成,该用户可重复访问该值(通过 CURRVAL),即使其他用户已递增序列。
  2. 与表解耦
    • 序列独立于表存在,因此同一序列可服务于一个或多个表
    • 某些序列号可能看似“跳过”,因为它们已在回滚的事务中被生成并使用。
    • 单个用户可能无法察觉其他用户正在使用同一序列。
  3. 访问序列值
    • 创建序列后,可通过以下伪列在 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 | NOMINVALUE
MAXVALUE:序列的最大值。若为 NOMAXVALUE,递增序列上限为 10^27,递减为 -1。

MINVALUE:序列的最小值。若为 NOMINVALUE,递减序列下限为 -10^26,递增为 1。

若同时省略 MAXVALUE 和 MINVALUE,默认允许的最大值/最小值由步长方向决定。
NOMAXVALUE

NOMINVALUE
CYCLE | 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;
  1. CURRVAL 总是返回当前SEQUENCE的值,但是在第一次NEXTVAL初始化之后才能使用CURRVAL,否则会出错。
  2. 第一次NEXTVAL返回的是初始值;随后的NEXTVAL会自动增加你定义的INCREMENT BY值,然后返回增加后的值。一次NEXTVAL会增加SEQUENCE的值,所以如果你在同一个语句里面使用多个NEXTVAL,其值就是不一样的。
  3. 在序列中设置了cycle(循环)时,当sequence的值达到maxvalue(最大值)后会从minvalue(最小值)开始循环(minvalue在不设置时默认为1)。
  4. 创建序列后,不能使用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 | NOMAXVALUEMAXVALUE integer:设置序列的最大值

NOMAXVALUE:指定序列没有最大值限制(默认值)
MINVALUE integer | NOMINVALUEMINVALUE integer:设置序列的最小值

NOMINVALUE:指定序列没有最小值限制(默认值)
CYCLE | NOCYCLECYCLE:允许序列在达到极值后循环

NOCYCLE:禁止序列循环(默认值)
CACHE integer | NOCACHECACHE integer:指定预分配的序列值数量(性能优化)

NOCACHE:禁用序列值缓存
ORDER | NOORDERORDER:确保序列值按请求顺序生成(RAC环境)

NOORDER:不保证序列值顺序(默认值)
SESSION | GLOBALSESSION:序列仅在当前会话中有效

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 VALUEidentity_options 特有的参数,仅可在 ALTER TABLE MODIFY 中使用。

注意:创建标识列时,Oracle 建议将 CACHE 值设为大于默认值 20,以提高性能。
   

使用限制:

  1. 数量限制:每张表只能有一个Identity标识列。
  2. 数据类型限制:必须为数值类型(如NUMBER、INTEGER),不能是用户自定义类型。
  3. 默认值冲突:不能同时在列定义中指定DEFAULT子句。
  4. 隐式约束:系统会隐式添加NOT NULLNOT DEFERRABLE约束。若显式定义与之冲突的约束(如 NULL),将报错。
  5. 加密限制:若标识列被加密,加密算法可能被推断。Oracle 建议对标识列使用强加密算法。
  6. 继承限制:通过CREATE TABLE AS SELECT创建的表不会继承原列的标识属性。
       
       

数据字典视图:
SELECT * FROM USER_TAB_IDENTITY_COLS;      — 查看所有Identity列

   
   

案例:通过 Identity列方式 实现主键自动生成
选项ALWAYSBY DEFAULTBY 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主键设计的道路上少走弯路!如果觉得有用,欢迎点赞收藏,我们下期技术分享再见!🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奈斯DB

打赏到账,我飘啦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值