kingbaseES- 序列(Sequence)
kingbaseES 中的序列是一个数据库对象,本质上是一个自增器。因此,序列在其他同类型数据库软件中以 autoincrment 值的形式存在。在一张表需要非随机,唯一标识符的场景下,Sequence 非常有用。 Sequence 对象中包含当前值,和一些独特属性,例如如何递增(或者递减)。实际上,Sequence 是不能被直接访问到的;他们需要通过 kingbaseES 中的相关函数来操作他们。
复制
数据库版本:
prod=# select version(); version --------------------------------------------------------------------------------------------------------------- Kingbase V008R003C002B0061 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46), 64 -bit (1 row)
复制
一、创建序列
看看创建的语法:
CREATE SEQUENCE sequencename [ INCREMENT increment ] -- 自增数,默认是 1 [ MINVALUE minvalue ] -- 最小值 [ MAXVALUE maxvalue ] -- 最大值 [ START start ] -- 设置起始值 [ CACHE cache ] -- 是否预先缓存 [ CYCLE ] -- 是否到达最大值的时候,重新返回到最小值
复制
Sequence 使用的是整型数值,因此它的取值范围是 [-2147483647, 2147483647] 之间;现在我们创建一个简单的序列:
prod=# create sequence seq1 prod-# increment 10 prod-# maxvalue 100 prod-# start 1 prod-# cache 5 prod-# cycle; CREATE SEQUENCE
复制
二、查看序列
ksql 的 \d 命令输出一个数据库对象,包括 Sequence,表,视图和索引。你还可以使用 \ds 命令只查看当前数据库的所有序列。例如:
prod=# \ds List of relations Schema | Name | Type | Owner --------+---------------+----------+-------- PUBLIC | employ_id_SEQ | sequence | SYSTEM PUBLIC | seq1 | sequence | SYSTEM PUBLIC | tb1_id_SEQ | sequence | SYSTEM (3 rows)
复制
Sequence 就像表和视图一样,拥有自己的结构,只不过它的结构是固定的:
prod=# \d seq1 Sequence "PUBLIC.seq1" Column | Type | Value ---------------+---------+------- SEQUENCE_NAME | NAME | seq1 LAST_VALUE | BIGINT | 1 START_VALUE | BIGINT | 1 INCREMENT_BY | BIGINT | 10 MAX_VALUE | BIGINT | 100 MIN_VALUE | BIGINT | 1 CACHE_VALUE | BIGINT | 5 LOG_CNT | BIGINT | 0 IS_CYCLED | BOOLEAN | t IS_CALLED | BOOLEAN | f
复制
我们现在查询下 seq1的 last_value(当前的序列值)和 increment_by (当 nextval() 被调用,当前值将会被增加)。
pigdb=# SELECT last_value, increment_by FROM seq1; last_value | increment_by ------------+-------------- 0 | 10 (1 row)
复制
由于序列刚刚被创建,因此 last_value 被设置成 10。
三、使用序列
我们需要知道的 Sequence 的函数使用:
nextval(‘sequence_name’): 将当前值设置成递增后的值,并返回
currval(‘sequence_name’): 返回当前值
setval(‘sequence_name’, n, b=true): 设置当前值;b 默认设置 true,下一次调用 nextval() 时,直接返回 n,如果设置 false,则返回 n+increment:
nextval() 函数要求一个序列名(必须由单引号包围)为第一个参数。 需要注意的是,当你第一次调用 nextval() 将会返回序列的初始值,即 START;因为他没有调用递增的方法。
prod=# select nextval('PUBLIC.seq1'); nextval --------- 1 (1 row) prod=# select currval('PUBLIC.seq1'); currval --------- 1 (1 row)
复制
Sequence 一般作为表的唯一标识符字段的默认值使用(这是序列的最常见的场景);看个例子:
prod=# create table t3 (id int not null default nextval('seq1'),name varchar(10)); CREATE TABLE prod=# \d t3 Table "PUBLIC.t3" Column | Type | Modifiers --------+----------------------------+-------------------------------------------- id | INTEGER | not null default NEXTVAL('seq1'::REGCLASS) name | CHARACTER VARYING(10 byte) |
复制
这张表中的 id 字段的默认值将被设置成 seq1 的 nextval() 值。如果插入值的时候,没有指定 id 的值,将会自动选择 nextval(‘seq1’) 的值。
注意: id 字段的默认值并不是强制使用的。用户仍然可以手动插入值,这样潜在地造成与未来的序列值冲突的风险。这个可以通过 trigger 来防止这个问题,后续将详细介绍。
为了防止同一个序列同时被多个被多个用户访问导致错误,序列的当前值与 session 关联。两个用户可能在两个不同的会话访问同一个序列,但是调用 currval() 时,只会返回同一会话下的当前值。
现在看看 curval() 的简单用法:
prod=# select currval('seq1'); currval --------- 11 (1 row) prod=# select * from t3 where id=currval('seq1'); id | name ----+-------- 11 | tom 11 | ellen5 (2 rows)
复制
另外,一个序列也可以通过 setval() 将 last_value 设置成任意值(必须在序列的取值范围内)。这个要求一个序列名(必须由单引号包围着)作为第一个参数,以及要设置的最后值作为第二个参数;看几个例子:
prod=# insert into t3 values (default,'tom'); INSERT 0 1 prod=# insert into t3(name) values ('jerry'); INSERT 0 1 prod=# select * from t3; id | name ----+------- 11 | tom 21 | jerry (2 rows)
复制
setval()
前文中,我们还提到了 setval() 的第三个参数;现在把它设置成 false和true,验证下效果:
prod=# select setval('seq1',110,false); 错误: setval: 值 110 超出序列 "seq1" 的范围 (1..100) # false prod=# select setval('seq1',50,false); setval -------- 50 (1 row) # nextval生成的setval的值 prod=# select nextval('seq1'); nextval --------- 50 (1 row) prod=# select nextval('seq1'); nextval --------- 60 (1 row) # true prod=# select setval('seq1',40,true); setval -------- 40 (1 row) # nextval生成的时setval+increment prod=# select nextval('seq1'); nextval --------- 50 (1 row)
复制
当第三个参数设置成 false 的时候,就像重新创建序列时,第一次调用的时候,只是初始化 last_val,不会调用递增函数。
序列循环 Cycle
在创建序列时,如果指定了maxvlaue和cycle参数,当nextval达到最大值时,从minvalue开始循环(默认值为1)。
prod=# insert into t3(name) values (‘ellen3’),(‘ellen4’),(‘ellen5’);
INSERT 0 3
prod=# select * from t3;
id | name
----±-------
11 | tom
21 | jerry
31 | rose
41 | rose
51 | ellen
61 | ellen1
71 | ellen2
81 | ellen3
91 | ellen3
1 | ellen4
11 | ellen5
21 | ellen3
31 | ellen4
41 | ellen5
(14 rows)
序列缓存 Cache
在建立序列时如果指定了cache n,当生成序列值时,会在缓存中生成n个值供调用,不同的session的cache可以产生相同的值(和Oracle不同)。
复制
#当前会话调用的序列值
prod=# insert into t3(name) values (‘ellen3’),(‘ellen4’),(‘ellen5’);
INSERT 0 3
prod=# select * from t3;
id | name
----±-------
11 | tom
21 | jerry
31 | rose
41 | rose
51 | ellen
61 | ellen1
71 | ellen2
81 | ellen3
91 | ellen3
1 | ellen4
11 | ellen5
21 | ellen3
31 | ellen4
41 | ellen5
(14 rows)
#另外session调用的序列值
prod=# select nextval('seq1'); nextval --------- 1 (1 row) prod=# select nextval('seq1'); nextval --------- 11 (1 row) prod=# select nextval('seq1'); nextval --------- 21 (1 row) prod=# select nextval('seq1'); nextval --------- 31 (1 row) prod=# select nextval('seq1'); nextval --------- 41 (1 row) prod=# select nextval('seq1'); nextval --------- 51 (1 row)
复制
四、删除序列
你可以使用:
DROP SEQUENCE seq_name[, …]
来删除一个或者多个序列。命令中的 seq_name 是序列名,不须被引号包围;如果是多个序列,可以使用逗号隔开。
现在我们试一下这个命令:
prod=# drop sequence seq1;
错误: 无法删除 序列 seq1 因为有其它对象倚赖它
DETAIL: 表 t3 字段 id的缺省 倚赖于 序列 seq1
HINT: 使用 DROP … CASCADE 把倚赖对象一并删除.
这里报错了,由于该序列被其他对象引用,因此无法直接删除,除非你使用 DROP … CASCADE。
我们可以使用下面的语句来查看的序列是否被数据库中的其他对象引用,:
prod=# SELECT s.relname, a.adsrc FROM sys_class s
prod-# JOIN sys_attrdef a on (s.relfilenode = a.adrelid)
prod-# WHERE a.adsrc ~ ‘seq1’;
relname | adsrc
---------±--------------------------
t3 | NEXTVAL(‘seq1’::REGCLASS)
(1 row)
这里检查到 seq1 序列被 t3 引用。你可以把这个序列名替换成任何一个你想查看的序列;或者不添加任何条件查看当前数据库中所有序列的引用。
现在我们成功地执行一次序列删除:
prod=# drop sequence seq1 cascade;
注意: 递归删除 表 t3 字段 id的缺省
DROP SEQUENCE
prod=# \d t3
Table “PUBLIC.t3”
Column | Type | Modifiers
--------±---------------------------±----------
id | INTEGER | not null
name | CHARACTER VARYING(10 byte) |
评论
