百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

数据库(Oracle)序列(Sequence)的基本使用

moboyou 2025-03-09 17:26 25 浏览

1. Sequence 定义

在Oracle中可以用SEQUENCE生成自增字段。Sequence序列是Oracle中用于生成数字序列的对象,可以创建一个唯一的数字作为主键。

2. 为什么要用 Sequence

你可能有疑问为什么要使用序列?

不能使用一个存储主键的表并每次递增吗?或者将列设置为AUTO INCREMENT?

如果使用一个表来储存主键值的话,也许需要这样做:

  1. 创建一个新表来储存单一值。
  2. 每次插入新值到你想要插入的表时,在新表中使用该值。
  3. 然后更新新表(将其加1)。
  4. 这些逻辑都可以加入进存储过程。

然而这种方法存在以下几个问题:

  1. 如果你的事务中途失败,可能会得到重复的数据(插入的数据有一个ID,但新表没有增加)。这可以通过先递增然后插入来部分避免,但它仍然有中途失败的风险。
  2. 更新表将对其进行锁定,这可能会导致多个事务或用户出现问题。如果有一个用户,这可能是可以的,但如果程序有两个或多个用户,那么这可能会导致问题。
  3. 创建和维护一个表以及执行此操作的代码是繁重的工作。

Sequence是一个更好的方法,原因如下:

  1. 创建更简单。
  2. 使用起来更简单。
  3. 没有死锁以及导致其他事务出现问题的风险。

3. 创建(CREATE)Sequence

CREATE SEQUENCE [schema_name.]{sequence_name}    -- schema_name为将存储序列的模式名,sequence_name 为自定义名称;
	START WITH      n    -- n 为序列的初始值,默认为1;
	INCREMENT BY    n    -- n 为序列步长(序列增加的幅度),默认为1,如果是负则按此步长递减;
	[MINVALUE n | NOMINVALUE ]    -- 如果序列递减,定义序列生成器能产生的最小值,默认为1
	[MAXVALUE n | NOMAXVALUE ]    -- 定义序列生成器能产生的最大值,默认无限制(1e28 - 1)
	[CACHE n | NOCACHE]    -- value 是存放序列的内存块大小,默认20。对序列进行内存缓存可以改善序列性能。
	[ORDER | NOORDER]    -- 表示序列号是按照请求的顺序生成的。如果使用时间戳的序列号会有用。
	[CYCLE | NOCYCLE]    -- 值达到限制值后是否循环,如果不循环,达到限制值后,继续产生新值会发生错误 ;

使用缓存创建序列的缺点是,如果发生系统故障,所有未使用的缓存序列值都将“丢失”。这会在指定的序列值中产生“间隙”。当系统恢复时,Oracle将从序列中停止的位置缓存新数字,忽略所谓的“丢失”序列值。要恢复丢失的序列值,您可以始终执行ALTER sequence命令,将计数器重置为正确的值。

4. 使用 Sequence

CURRVAL和NEXTVAL可以在以下几个地方使用:

  • INSERT语句的VALUES子句。
  • SELECT语句的SELECT列表
  • UPDATE语句的UPDATE子句

它们不能在以下地方使用:

  • CHECK约束的条件
  • 视图查询
  • 实体化视图查询
  • 子查询
  • 带有DISTINCT关键字、GROUP BY子句或ORDER BY子句的SELECT语句
  • 使用UNION、INTERSECT或MINUS运算符与另一个SELECT语句组合的SELECT语句
  • SELECT语句的WHERE子句
  • CREATE TABLE或ALTER TABLE语句中列的DEFAULT值

最后一点意味着您不能使用DEFAULT关键字的序列将列设置为自动递增。有一种方法可以创建自动递增列,那就是使用触发器和序列。

1)基本Oracle序列示例

以下语句创建一个名为id_seq的升序Sequence,从10开始,递增10,最小值为10,最大值为100。由于CYCLE选项,序列一旦达到100就返回10。

CREATE SEQUENCE id_seq
    INCREMENT BY 10
    START WITH 10
    MINVALUE 10
    MAXVALUE 100
    CYCLE
    CACHE 2;

使用NEXTVAL伪列获取序列的下一个值:

SELECT 
    id_seq.NEXTVAL 
FROM 
    dual;
以下是输出:
    NEXTVAL
----------
        10        

一旦通过NEXTVAL伪列获取序列号,就可以使用CURRVAL伪列重复访问它:

SELECT 
    id_seq.CURRVAL 
FROM 
    dual;
以下是输出:
    CURRVAL
----------
        10

注意!当调用NEXTVAL伪列时,它会为正在选择或插入的每一行数据返回一个新值。:

SELECT 
    id_seq.NEXTVAL 
FROM 
    dual;
以下是输出:
    NEXTVAL
----------
        20

但如果我使用几个NEXTVAL命令运行此查询的话:

SELECT id_seq.NEXTVAL AS nv1,
id_seq.NEXTVAL AS nv2,
id_seq.NEXTVAL AS nv3
FROM dual;
以下是输出:
       NV1         NV2         NV3
----------  ----------  ----------
        30          30          30

这表明NEXTVAL只为此记录调用过一次,并且每次的值都是相同的。

2) 在表列中使用 Sequence 的例子

在Oracle12c之前,只能在插入时将序列与表列间接关联。

首先,创建一个名为tasks的新表:

CREATE TABLE tasks(
    id NUMBER PRIMARY KEY,
    title VARCHAR2(255) NOT NULL
);

其次,为tasks表的id列创建一个序列:

CREATE SEQUENCE task_id_seq;

第三,在任务表中插入数据:

INSERT INTO tasks(id, title)
VALUES(task_id_seq.NEXTVAL, 'Create Sequence in Oracle');

INSERT INTO tasks(id, title)
VALUES(task_id_seq.NEXTVAL, 'Examine Sequence Values');

最后,从任务表中查询数据:

SELECT  
    id, title
FROM
    tasks;

添加图片注释,不超过 140 字(可选)

在本例中,tasks表与task_id_seq序列没有直接关联。

3)通过标识列使用序列的例子

在Oracle12c中,您可以通过标识列将序列与表列相关联。

首先,用id列的identity列创建tasks表。

CREATE TABLE tasks(
    id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    title VARCHAR2(255) NOT NULL
);

Oracle创建了一个与 tasks表 的 id列 关联的序列。

由于Oracle自动为 id列 生成序列,因此在您的Oracle实例中,序列的名称可能不同。

Oracle创建序列-标识列

添加图片注释,不超过 140 字(可选)

Oracle使用 sys.idnseq$ 来存储表和序列之间的链接。

此查询返回任务表和 ISEQ$_74366序列 的关联:

SELECT 
    a.name AS table_name,
    b.name AS sequence_name
FROM   
    sys.idnseq$ c
    JOIN obj$ a ON c.obj# = a.obj#
    JOIN obj$ b ON c.seqobj# = b.obj#
WHERE 
    a.name = 'TASKS';  

第二,在任务表中插入一些行:

INSERT INTO tasks(title)
VALUES('Learn Oracle identity column in 12c');

INSERT INTO tasks(title)
VALUES('Verify contents of the tasks table');

最后,从任务表中查询数据:

SELECT
    id, title
FROM
    tasks;

添加图片注释,不超过 140 字(可选)

5. 删除(DROP)Sequence

要删除序列,它必须在您的模式中,或者您必须具有drop ANY sequence权限才能删除其他模式中的序列。

DROP SEQUENCE seq_name;

6. 更改(Alter)Sequence

创建序列后,可以更改序列的大多数特性。唯一不能更改的是序列的起始编号和序列的当前值。要更改的话需要删除并重新创建序列。

ALTER SEQUENCE seq02
INCREMENT BY 20
MAXVALUE 100000
CYCLE;

7. Sequence 原理

Oracle用Sequence来按需提供(几乎)无限的数字序列,这些序列保证是唯一的。最简单的方法就是保持一个全局可见的计数器,并在每次查询sequence_name.nextval的值时递增。

但Oracle必须跟踪提供的最后一个数字,以避免两次提供相同数字的风险——这对数据库系统来说很容易:只需将最新的数字保存在表中即可。然而,如果每次有人需要下一个号码时都必须更新一个表格,这流程会非常缓慢。这时应该使用一个自主事务,这样就不需要等待第一个会话提交其当前事务,然后才能生成下一个数字。因此,Oracle使用递归的、自主的事务来处理表更新,并且它通过在内存中计数并记住下一次需要更新表的时机来避免每次调用nextval都更新表。

自制”序列的一种常见策略是,在一个表中包含(序列名,最近使用的序列号)的列,然后编写一个函数,从表中选择相关行进行更新,增加编号,更新表,并将编号提供给最终用户,这正是Oracle内在的机制。

您可以通过查询视图 user_sequences 来查看序列的数据库映像。假设我刚刚创建了一个名为s1的序列,图3.1是一个查询创建序列后立即给出的结果,和一次调用获取 s1.nextval 后得到的结果:

select
        min_value, max_value, 
        increment_by, cache_size, last_number, 
        cycle_flag, order_flag
from 
        user_sequences
where 
        sequence_name = 'S1'
/

图7.1

如果你有DBA权限,你可以进一步找到序列的 object_id,然后查询视图所基于的字典表(seq$)。以下运行了两次查询,一次在第一次调用 s1.nextval 之前,另一次是刚刚调用 s1 之后:

select 
        minvalue, maxvalue, increment$, cache, highwater, cycle#, order$ 
from 
        seq$ 
where
        obj# = 124874
;

图7.2

如果你的账户已被授权,可以通过动态性能视图 v$_sequences 查看内存中的信息:

select
        min_value, max_value,
        increment_by, cache_size, highwater,
        cycle_flag, order_flag, nextvalue
from
        v$_sequences
where
        object# = 124874
/

第一次调用s1.nextval之后,我只查询了一次视图(在第一次调用nextval时,序列才会出现在视图中):

图7.3

动态性能视图的列 nextvalue 保存了下次用户调用 s1.nextval 时将提供的值。

三个视图中都有一个“highwater”值(在图7.1视图user_sequences中称为“last_number”)。当对s1.nextval 的调用返回 highwater 中显示的值(highwater和nextvalue相同)时,进行调用的会话将执行并提交递归事务,将增量值添加到当前 highwater 并更新 seq$ 表。

“缓存”不是传统意义上的缓存,它只是一对数字(无论您设置的序列缓存大小有多大):当前值和提升highwater 后的值。为序列设置大型缓存不会造成资源损失,所以在大多数情况下,您应该尽可能使用大的cache。

相关推荐

Excel技巧:SHEETSNA函数一键提取所有工作表名称批量生产目录

首先介绍一下此函数:SHEETSNAME函数用于获取工作表的名称,有三个可选参数。语法:=SHEETSNAME([参照区域],[结果方向],[工作表范围])(参照区域,可选。给出参照,只返回参照单元格...

Excel HOUR函数:“小时”提取器_excel+hour函数提取器怎么用

一、函数概述HOUR函数是Excel中用于提取时间值小时部分的日期时间函数,返回0(12:00AM)到23(11:00PM)之间的整数。该函数在时间数据分析、考勤统计、日程安排等场景中应用广泛。语...

Filter+Search信息管理不再难|多条件|模糊查找|Excel函数应用

原创版权所有介绍一个信息管理系统,要求可以实现:多条件、模糊查找,手动输入的内容能去空格。先看效果,如下图动画演示这样的一个效果要怎样实现呢?本文所用函数有Filter和Search。先用filter...

FILTER函数介绍及经典用法12:FILTER+切片器的应用

EXCEL函数技巧:FILTER经典用法12。FILTER+切片器制作筛选按钮。FILTER的函数的经典用法12是用FILTER的函数和切片器制作一个筛选按钮。像左边的原始数据,右边想要制作一...

office办公应用网站推荐_office办公软件大全

以下是针对Office办公应用(Word/Excel/PPT等)的免费学习网站推荐,涵盖官方教程、综合平台及垂直领域资源,适合不同学习需求:一、官方权威资源1.微软Office官方培训...

WPS/Excel职场办公最常用的60个函数大全(含卡片),效率翻倍!

办公最常用的60个函数大全:从入门到精通,效率翻倍!在职场中,WPS/Excel几乎是每个人都离不开的工具,而函数则是其灵魂。掌握常用的函数,不仅能大幅提升工作效率,还能让你在数据处理、报表分析、自动...

收藏|查找神器Xlookup全集|一篇就够|Excel函数|图解教程

原创版权所有全程图解,方便阅读,内容比较多,请先收藏!Xlookup是Vlookup的升级函数,解决了Vlookup的所有缺点,可以完全取代Vlookup,学完本文后你将可以应对所有的查找难题,内容...

批量查询快递总耗时?用Excel这个公式,自动计算揽收到签收天数

批量查询快递总耗时?用Excel这个公式,自动计算揽收到签收天数在电商运营、物流对账等工作中,经常需要统计快递“揽收到签收”的耗时——比如判断某快递公司是否符合“3天内送达”的服务承...

Excel函数公式教程(490个实例详解)

Excel函数公式教程(490个实例详解)管理层的财务人员为什么那么厉害?就是因为他们精通excel技能!财务人员在日常工作中,经常会用到Excel财务函数公式,比如财务报表分析、工资核算、库存管理等...

Excel(WPS表格)Tocol函数应用技巧案例解读,建议收藏备用!

工作中,经常需要从多个单元格区域中提取唯一值,如体育赛事报名信息中提取唯一的参赛者信息等,此时如果复制粘贴然后去重,效率就会很低。如果能合理利用Tocol函数,将会极大地提高工作效率。一、功能及语法结...

Excel中的SCAN函数公式,把计算过程理清,你就会了

Excel新版本里面,除了出现非常好用的xlookup,Filter公式之外,还更新一批自定义函数,可以像写代码一样写公式其中SCAN函数公式,也非常强大,它是一个循环函数,今天来了解这个函数公式的计...

Excel(WPS表格)中多列去重就用Tocol+Unique组合函数,简单高效

在数据的分析和处理中,“去重”一直是绕不开的话题,如果单列去重,可以使用Unique函数完成,如果多列去重,如下图:从数据信息中可以看到,每位参赛者参加了多项运动,如果想知道去重后的参赛者有多少人,该...

Excel(WPS表格)函数Groupby,聚合统计,快速提高效率!

在前期的内容中,我们讲了很多的统计函数,如Sum系列、Average系列、Count系列、Rank系列等等……但如果用一个函数实现类似数据透视表的功能,就必须用Groupby函数,按指定字段进行聚合汇...

Excel新版本,IFS函数公式,太强大了!

我们举一个工作实例,现在需要计算业务员的奖励数据,右边是公司的奖励标准:在新版本的函数公式出来之前,我们需要使用IF函数公式来解决1、IF函数公式IF函数公式由三个参数组成,IF(判断条件,对的时候返...

Excel不用函数公式数据透视表,1秒完成多列项目汇总统计

如何将这里的多组数据进行汇总统计?每组数据当中一列是不同菜品,另一列就是该菜品的销售数量。如何进行汇总统计得到所有的菜品销售数量的求和、技术、平均、最大、最小值等数据?不用函数公式和数据透视表,一秒就...