[目录]
参考
Oracle 序列
什么是序列
数据库对象的一种。通过序列生成连续的数字以此来实现主键字段的自己主动、唯一增长,而且一个序列可为多列、多表同一时候使用。
创建一个简单序列
例子:
--创建序列
create sequence seq_test --创建一个序列
minvalue 1 --最小值
maxvalue 100000 --最大值
start with 1 --指定序列起始数
increment by 1 --指定序列增长步长
cache 20 --指定数据库内存中预分配的序列值个数,以便高速获取。最小cache值为2
测试序列
--测试序列
select seq_test.nextval as 下一个值 from dual;
select seq_test.currval as 当前值 from dual
创建语法说明
increment by
:指定序列增长步长。能够为正(升序)、负整数(降序)。但不能为0。最高精度28。
start with
: 指定序列起始数。默觉得序列最小值。
maxvalue
:指定序列最大值。最大28位。必须大于等于起始值且大于等于序列最小值。
nomaxvalue
无最大值(实际为10^27或-1)。默认。
minvalue
:指定序列最小值。
nominvalue
:无最小值(实际为1或-10^26)。默认。
cycle
:指定序列达到最大值或最小值后继续从头开始生成。带有cycle条件序列当达到最大值后,下一个值从最小值 minvalue 开始循环!
例子:
create sequence seq_test --创建一个序列
minvalue 1 --最小值
maxvalue 100000 --最大值
start with 1 --指定序列起始数
increment by 1 --指定序列增长步长
cycle --指定序列达到最大值或最小值后继续从头开始生成
cache 20 --指定数据库内存中预分配的序列值个数,以便高速获取。最小cache值为2
nocycle
:不循环生成。默认。
cache
:指定数据库内存中预分配的序列值个数,以便高速获取。最小 cache 值为2。假设系统发生问题。全部缓存的没有被 DML 语句使用并提交的序列值将丢失。潜在丢失值数量等于 cache 的数量。cache 参数最大值为:(cell(maxvalue - minvalue)) / abs(increment)
nocache
:不指定缓存数,默认缓存20。
order
:指定 order 条件保证序列按请求顺序生成。
此条件适用于 rac 环境。
noorder
:不保证序列按请求顺序生成。
授权序列
grant select on seq_test to luoma with grant option;
grant select on seq_test to luoma;
修改语法说明
语法说明:
1.想以不同的数字又一次开始序列,必须删除重建
例如上面创建的例子中的序列修改为 55:
alter sequence seq_test start with 55 --修改序列起始数
执行提示:
ORA-02293:无法变更启动序列号
2.改动的 maxvalue 必须大于序列当前值
例如:
alter sequence seq_test maxvalue 1 --修改序列最大值
执行提示:
ORA-04004:MINVALUE 必须小于 MAXVALUE
删除语法说明
例子:
drop sequence seq_test--删除序列
手动序列
案例:客户化系统单据序列操作的 API
序列对应表-COMMON_DOC_SEQUENCES
-- Create table
create table COMMON_DOC_SEQUENCES
(
doc_type VARCHAR2(45) not null,
pk1_value VARCHAR2(50) not null,
pk2_value VARCHAR2(50),
pk3_value VARCHAR2(50),
pk4_value VARCHAR2(75),
pk5_value VARCHAR2(50),
next_seq_number NUMBER,
created_by NUMBER not null,
creation_date DATE not null,
last_updated_by NUMBER not null,
last_update_date DATE not null,
last_update_login NUMBER
);
-- Create/Recreate indexes
create unique index COMMON_DOC_SEQUENCES_N1 on COMMON_DOC_SEQUENCES (DOC_TYPE, PK1_VALUE, PK2_VALUE, PK3_VALUE, PK4_VALUE, PK5_VALUE);
序列对应包
CREATE OR REPLACE PACKAGE "COMMON_DOC_SEQUENCE_UTL" AS
/*==================================================
Program Name:
COMMON_DOC_SEQUENCE_UTL
Description:
该程序包提供客户化系统单据序列操作的 API
History:
==================================================*/
/*==================================================
Function Name :
next_seq_number
Description:
获取下一个单据号
Argument:
p_doc_type : 单据类型
p_pk1_value : 主关键字1
p_pk2_value : 主关键字2
p_pk3_value : 主关键字3
p_pk4_value : 主关键字4
p_pk5_value : 主关键字5
p_init_number : 初始序列号
Return:
NUMBER : 返回单据号序列
History:
==================================================*/
FUNCTION next_seq_number
(
p_doc_type IN VARCHAR2,
p_pk1_value IN VARCHAR2 DEFAULT NULL,
p_pk2_value IN VARCHAR2 DEFAULT NULL,
p_pk3_value IN VARCHAR2 DEFAULT NULL,
p_pk4_value IN VARCHAR2 DEFAULT NULL,
p_pk5_value IN VARCHAR2 DEFAULT NULL,
p_init_number IN NUMBER DEFAULT 1
) RETURN NUMBER;
/*==================================================
Function Name :
next_seq_number
Description:
获取下一个单据号
Argument:
p_doc_type : 单据类型
p_doc_prefix :前缀
p_seq_length : 长度
p_pk1_value : 主关键字1
p_pk2_value : 主关键字2
p_pk3_value : 主关键字3
p_pk4_value : 主关键字4
p_pk5_value : 主关键字5
p_init_number : 初始序列号
Return:
VARCHAR2 : 返回单据号
History:
==================================================*/
FUNCTION next_seq_number
(
p_doc_type IN VARCHAR2,
p_doc_prefix IN VARCHAR2,
p_seq_length IN NUMBER DEFAULT 0,
p_pk1_value IN VARCHAR2 DEFAULT NULL,
p_pk2_value IN VARCHAR2 DEFAULT NULL,
p_pk3_value IN VARCHAR2 DEFAULT NULL,
p_pk4_value IN VARCHAR2 DEFAULT NULL,
p_pk5_value IN VARCHAR2 DEFAULT NULL,
p_init_number IN NUMBER DEFAULT 1
) RETURN VARCHAR2;
/*==================================================
Function Name :
next_seq_number
Description:
获取当前单据号
Argument:
p_doc_type : 单据类型
p_doc_prefix :前缀
p_seq_length : 长度
p_pk1_value : 主关键字1
p_pk2_value : 主关键字2
p_pk3_value : 主关键字3
p_pk4_value : 主关键字4
p_pk5_value : 主关键字5
p_init_number : 初始序列号
Return:
VARCHAR2 : 返回单据号
History:
==================================================*/
FUNCTION curr_seq_number
(
p_doc_type IN VARCHAR2,
p_doc_prefix IN VARCHAR2,
p_seq_length IN NUMBER DEFAULT 0,
p_pk1_value IN VARCHAR2 DEFAULT NULL,
p_pk2_value IN VARCHAR2 DEFAULT NULL,
p_pk3_value IN VARCHAR2 DEFAULT NULL,
p_pk4_value IN VARCHAR2 DEFAULT NULL,
p_pk5_value IN VARCHAR2 DEFAULT NULL,
p_init_number IN NUMBER DEFAULT 1
) RETURN VARCHAR2;
END COMMON_DOC_SEQUENCE_UTL;
/
CREATE OR REPLACE PACKAGE BODY "COMMON_DOC_SEQUENCE_UTL" AS
/*==================================================
Program Name:
COMMON
Description:
该程序包提供客户化系统单据序列操作的API
History:
==================================================*/
FUNCTION next_seq_number
(
p_doc_type IN VARCHAR2,
p_pk1_value IN VARCHAR2 DEFAULT NULL,
p_pk2_value IN VARCHAR2 DEFAULT NULL,
p_pk3_value IN VARCHAR2 DEFAULT NULL,
p_pk4_value IN VARCHAR2 DEFAULT NULL,
p_pk5_value IN VARCHAR2 DEFAULT NULL,
p_init_number IN NUMBER DEFAULT 1
) RETURN NUMBER IS
PRAGMA AUTONOMOUS_TRANSACTION;
l_doc_type VARCHAR2(30);
CURSOR c_seq_del IS
SELECT *
FROM (SELECT ds.rowid row_id
,ds.next_seq_number
FROM COMMON_DOC_SEQUENCES ds
WHERE ds.doc_type = l_doc_type
AND ds.pk1_value = nvl(p_pk1_value, '-1')
AND ds.pk2_value = nvl(p_pk2_value, '-1')
AND ds.pk3_value = nvl(p_pk3_value, '-1')
AND ds.pk4_value = nvl(p_pk4_value, '-1')
AND ds.pk5_value = nvl(p_pk5_value, '-1')
ORDER BY ds.next_seq_number) tt
WHERE rownum = 1;
CURSOR c_seq IS
SELECT ds.rowid row_id
,ds.next_seq_number
FROM COMMON_DOC_SEQUENCES ds
WHERE ds.doc_type = p_doc_type
AND ds.pk1_value = nvl(p_pk1_value, '-1')
AND ds.pk2_value = nvl(p_pk2_value, '-1')
AND ds.pk3_value = nvl(p_pk3_value, '-1')
AND ds.pk4_value = nvl(p_pk4_value, '-1')
AND ds.pk5_value = nvl(p_pk5_value, '-1')
FOR UPDATE; -- NOWAIT;
l_row_id VARCHAR2(18);
l_next_seq_number NUMBER;
BEGIN
l_doc_type := p_doc_type || 'DEL';
--先看是否存在删除的数据
OPEN c_seq_del;
FETCH c_seq_del
INTO l_row_id
,l_next_seq_number;
IF c_seq_del%NOTFOUND THEN
--不存在断号
OPEN c_seq;
FETCH c_seq
INTO l_row_id
,l_next_seq_number;
IF c_seq%NOTFOUND THEN
l_next_seq_number := nvl(p_init_number, 1);
INSERT INTO COMMON_DOC_SEQUENCES
(doc_type
,pk1_value
,pk2_value
,pk3_value
,pk4_value
,pk5_value
,next_seq_number
,creation_date
,created_by
,last_update_date
,last_updated_by
,last_update_login)
VALUES
(p_doc_type
,nvl(p_pk1_value, '-1')
,nvl(p_pk2_value, '-1')
,nvl(p_pk3_value, '-1')
,nvl(p_pk4_value, '-1')
,nvl(p_pk5_value, '-1')
,l_next_seq_number
,SYSDATE
,1
,SYSDATE
,1
,1);
ELSE
l_next_seq_number := l_next_seq_number + 1;
UPDATE COMMON_DOC_SEQUENCES
SET next_seq_number = l_next_seq_number,
last_update_date = SYSDATE,
last_updated_by = 1,
last_update_login = 1
WHERE ROWID = l_row_id;
END IF;
CLOSE c_seq;
ELSE
--用删除掉的编号
DELETE FROM COMMON_DOC_SEQUENCES WHERE ROWID = l_row_id;
END IF;
COMMIT;
RETURN l_next_seq_number;
END next_seq_number;
FUNCTION next_seq_number
(
p_doc_type IN VARCHAR2,
p_doc_prefix IN VARCHAR2,
p_seq_length IN NUMBER DEFAULT 0,
p_pk1_value IN VARCHAR2 DEFAULT NULL,
p_pk2_value IN VARCHAR2 DEFAULT NULL,
p_pk3_value IN VARCHAR2 DEFAULT NULL,
p_pk4_value IN VARCHAR2 DEFAULT NULL,
p_pk5_value IN VARCHAR2 DEFAULT NULL,
p_init_number IN NUMBER DEFAULT 1
) RETURN VARCHAR2 IS
l_next_seq_number NUMBER;
l_doc_number VARCHAR2(150);
BEGIN
l_next_seq_number := next_seq_number(p_doc_type => p_doc_type,
p_pk1_value => p_pk1_value,
p_pk2_value => p_pk2_value,
p_pk3_value => p_pk3_value,
p_pk4_value => p_pk4_value,
p_pk5_value => p_pk5_value,
p_init_number => p_init_number);
IF p_seq_length IS NULL OR p_seq_length = 0 THEN
l_doc_number := p_doc_prefix || l_next_seq_number;
ELSE
IF length(l_next_seq_number) >= p_seq_length THEN
l_doc_number := p_doc_prefix || l_next_seq_number;
ELSE
l_doc_number := p_doc_prefix || lpad(l_next_seq_number, p_seq_length, '0');
END IF;
END IF;
RETURN l_doc_number;
END next_seq_number;
FUNCTION curr_seq_number
(
p_doc_type IN VARCHAR2,
p_doc_prefix IN VARCHAR2,
p_seq_length IN NUMBER DEFAULT 0,
p_pk1_value IN VARCHAR2 DEFAULT NULL,
p_pk2_value IN VARCHAR2 DEFAULT NULL,
p_pk3_value IN VARCHAR2 DEFAULT NULL,
p_pk4_value IN VARCHAR2 DEFAULT NULL,
p_pk5_value IN VARCHAR2 DEFAULT NULL,
p_init_number IN NUMBER DEFAULT 1
) RETURN VARCHAR2 IS
PRAGMA AUTONOMOUS_TRANSACTION;
CURSOR c_seq IS
SELECT ds.rowid row_id
,ds.next_seq_number
FROM COMMON_DOC_SEQUENCES ds
WHERE ds.doc_type = p_doc_type
AND ds.pk1_value = nvl(p_pk1_value, '-1')
AND ds.pk2_value = nvl(p_pk2_value, '-1')
AND ds.pk3_value = nvl(p_pk3_value, '-1')
AND ds.pk4_value = nvl(p_pk4_value, '-1')
AND ds.pk5_value = nvl(p_pk5_value, '-1')
FOR UPDATE; -- NOWAIT;
l_row_id VARCHAR2(18);
l_next_seq_number NUMBER;
BEGIN
OPEN c_seq;
FETCH c_seq
INTO l_row_id
,l_next_seq_number;
IF c_seq%NOTFOUND THEN
l_next_seq_number := next_seq_number(p_doc_type => p_doc_type,
p_doc_prefix => NULL,
p_seq_length => p_seq_length,
p_pk1_value => p_pk1_value,
p_pk2_value => NULL,
p_pk3_value => NULL,
p_pk4_value => NULL,
p_pk5_value => NULL,
p_init_number => 1);
INSERT INTO COMMON_DOC_SEQUENCES
(doc_type
,pk1_value
,pk2_value
,pk3_value
,pk4_value
,pk5_value
,next_seq_number
,creation_date
,created_by
,last_update_date
,last_updated_by
,last_update_login)
VALUES
(p_doc_type
,nvl(p_pk1_value, '-1')
,nvl(p_pk2_value, '-1')
,nvl(p_pk3_value, '-1')
,nvl(p_pk4_value, '-1')
,nvl(p_pk5_value, '-1')
,l_next_seq_number
,SYSDATE
,1
,SYSDATE
,1
,1);
END IF;
IF p_seq_length IS NULL OR p_seq_length = 0 THEN
l_next_seq_number := p_doc_prefix || l_next_seq_number;
ELSE
IF length(l_next_seq_number) >= p_seq_length THEN
l_next_seq_number := p_doc_prefix || l_next_seq_number;
ELSE
l_next_seq_number := p_doc_prefix || lpad(l_next_seq_number, p_seq_length, '0');
END IF;
END IF;
CLOSE c_seq;
COMMIT;
RETURN l_next_seq_number;
END curr_seq_number;
END COMMON_DOC_SEQUENCE_UTL;
/
使用案例
--流水号获取
declare
var_no number;
var_no_str varchar2(100);
begin
--单独的号码
var_no := COMMON_DOC_SEQUENCE_UTL.next_seq_number('PAYMENT_WRITE_OFF','BATCHID-INVOICE_NO_NUMBER','','','','',1);
dbms_output.put_line(var_no);
--带数量的前缀
var_no_str := COMMON_DOC_SEQUENCE_UTL.next_seq_number('PAYMENT_WRITE_OFF','-',3,'BATCHID-SAVEPREPAYAPPLYDATA','','','','',1);
dbms_output.put_line(var_no_str);
end;
第一次调用
1
-001
第二次调用
2
-002
查询生成结果
--验证
select t.*,t.rowid
from common_doc_sequences t
where doc_type = 'PAYMENT_WRITE_OFF'