一:postgresql 序列概述
序列对象(也叫序列生成器)就是用CREATE SEQUENCE 创建的特殊的单行表。一个序列对象通常用于为行或者表生成唯一的标识符。pg 序列不同于mysql自增主键,一个序列可以被多个表使用,可以被同一张表里的多个字段使用,如下:
--创建序列
db_01=# CREATE SEQUENCE cmp_dac.test_seq
db_01-# START WITH 1
db_01-# INCREMENT BY 1
db_01-# NO MINVALUE
db_01-# NO MAXVALUE
db_01-# CACHE 1;
CREATE SEQUENCE
--查看序列
db_01=# \d cmp_dac.test_seq
Sequence "cmp_dac.test_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
--------+-------+---------+---------------------+-----------+---------+-------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
--创建表时直接引用已经创建的序列
db_01=# CREATE TABLE cmp_dac.test_1 (
db_01(# id bigint DEFAULT nextval('cmp_dac.test_seq'::regclass) NOT NULL,
db_01(# cust_id bigint NOT NULL,
db_01(# name character varying(20) NOT NULL,
db_01(# updatetime timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
db_01(# );
CREATE TABLE
-- 创建表后使用alter 语句指定int类型列使用序列(同一个序列可以被多个表使用)
db_01=# CREATE TABLE cmp_dac.test_2 (
db_01(# id bigint DEFAULT 0 NOT NULL,
db_01(# cust_id bigint NOT NULL,
db_01(# name character varying(20) NOT NULL,
db_01(# updatetime timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
db_01(# );
CREATE TABLE
db_01=# alter table cmp_dac.test_2 alter column id set default nextval('cmp_dac.test_seq');
ALTER TABLE
-- 同一个序列可以指定给同一张表的多个字段使用
db_01=# CREATE TABLE cmp_dac.test_3 (
db_01(# id bigint DEFAULT nextval('cmp_dac.test_seq'::regclass) NOT NULL,
db_01(# cust_id bigint DEFAULT nextval('cmp_dac.test_seq'::regclass) NOT NULL,
db_01(# name character varying(20) NOT NULL,
db_01(# updatetime timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
db_01(# );
CREATE TABLE
二:创建及使用序列
#postgresql 中两种创建和使用序列的方式
1. 隐式创建序列并使用
#建表时指定 serial 或者 bigserial 列类型会隐式的创建一个序列
#隐式序列和显式序列不同之处在于
1)隐式创建的序列,在被被删除时会被自动删除(删除表时,显式创建的序列不会被删除,除非使用ALTER SEQUENCE cmp_dac.test_seq OWNED BY cmp_dac.test_1.id; 语句指定序列被哪个列所有)
2)在迁移时不需要特别处理隐式序列
# serial 对应的是 integer,是 4 个字节,最大值是 2 147 483 647,即 21 亿左右。
# bigserial,即 bigint,8 个字节,最大值是 9 223 372 036 854 775 807,即 922亿个亿左右。这对于绝大多数场景是足够了,这也是 PostgreSQL 中 sequence 的最大值
db_01=# CREATE TABLE tb_test_bigserial (
db_01(# id BIGSERIAL PRIMARY KEY,
db_01(# create_time TIMESTAMP DEFAULT clock_timestamp()
db_01(# );
CREATE TABLE
db_01=# CREATE TABLE tb_test_serial (
db_01(# id SERIAL PRIMARY KEY,
db_01(# create_time TIMESTAMP DEFAULT clock_timestamp()
db_01(# );
CREATE TABLE
db_01=# \d tb_test_bigserial;
Table "public.tb_test_bigserial"
Column | Type | Collation | Nullable | Default
-------------+-----------------------------+-----------+----------+-----------------------------------------------
id | bigint | | not null | nextval('tb_test_bigserial_id_seq'::regclass)
create_time | timestamp without time zone | | | clock_timestamp()
Indexes:
"tb_test_bigserial_pkey" PRIMARY KEY, btree (id)
db_01=# \d tb_test_serial;
Table "public.tb_test_serial"
Column | Type | Collation | Nullable | Default
-------------+-----------------------------+-----------+----------+--------------------------------------------
id | integer | | not null | nextval('tb_test_serial_id_seq'::regclass)
create_time | timestamp without time zone | | | clock_timestamp()
Indexes:
"tb_test_serial_pkey" PRIMARY KEY, btree (id)
2.显示创建序列并使用
#序列的名字一般为 表名+列名+seq组成,隐式创建的序列也可以像显式建立的序列一样被其他列引用,一样可以被修改。
-- 序列创建语法
CREATE [ TEMPORARY | TEMP ] SEQUENCE name [ INCREMENT [ BY ] increment ]
[ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
[ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
[ OWNED BY { table.column | NONE } ]
-- 显示序列创建语句
CREATE SEQUENCE cmp_dac.test_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--创建表时直接引用已经创建的序列
db_01=# CREATE TABLE cmp_dac.test_1 (
db_01(# id bigint DEFAULT nextval('cmp_dac.test_seq'::regclass) NOT NULL,
db_01(# cust_id bigint NOT NULL,
db_01(# name character varying(20) NOT NULL,
db_01(# updatetime timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
db_01(# );
CREATE TABLE
-- 创建表后使用alter 语句指定int类型列使用序列(同一个序列可以被多个表使用)
db_01=# CREATE TABLE cmp_dac.test_2 (
db_01(# id bigint DEFAULT 0 NOT NULL,
db_01(# cust_id bigint NOT NULL,
db_01(# name character varying(20) NOT NULL,
db_01(# updatetime timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
db_01(# );
CREATE TABLE
db_01=# alter table cmp_dac.test_2 alter column id set default nextval('cmp_dac.test_seq');
ALTER TABLE
-- 给序列指定所有者(给显式序列指定所有者后,删除该表或者字段时,会自动删除该序列,如果该序列还被其他表引用,那么删除表或者字段的操作会失败)
db_01=# ALTER SEQUENCE cmp_dac.test_seq OWNED BY cmp_dac.test_1.id;
ALTER SEQUENCE
db_01=# alter table cmp_dac.test_1 drop column id;
ERROR: cannot drop column id of table cmp_dac.test_1 because other objects depend on it
DETAIL: default value for column id of table cmp_dac.test_2 depends on sequence cmp_dac.test_seq
default value for column id of table cmp_dac.test_3 depends on sequence cmp_dac.test_seq
default value for column cust_id of table cmp_dac.test_3 depends on sequence cmp_dac.test_seq
HINT: Use DROP ... CASCADE to drop the dependent objects too.
db_01=# drop table cmp_dac.test_1;
ERROR: cannot drop table cmp_dac.test_1 because other objects depend on it
DETAIL: default value for column id of table cmp_dac.test_2 depends on sequence cmp_dac.test_seq
default value for column id of table cmp_dac.test_3 depends on sequence cmp_dac.test_seq
default value for column cust_id of table cmp_dac.test_3 depends on sequence cmp_dac.test_seq
HINT: Use DROP ... CASCADE to drop the dependent objects too.
-- 删除序列的所有者
db_01=# ALTER SEQUENCE cmp_dac.test_seq OWNED BY NONE;
ALTER SEQUENCE
db_01=# alter table cmp_dac.test_1 drop column id;
ALTER TABLE
三. 查看序列
1)查看当前数据库库中的所有序列
-- 要先切换到对应数据库
\c db_01;
select * ?from pg_class where relkind='S';
--两张表的关联字段 pg_class.oid=pg_sequence.seqrelid
select * from pg_sequence;
2)查看序列属性
\d cmp_dac.test_seq;
\d cmp_dac.test_seq;
Sequence "cmp_dac.test_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
--------+-------+---------+---------------------+-----------+---------+-------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
3)查看序列(序列可以像表一样使用select查询)
select * from cmp_dac.test_seq;
select * from cmp_dac.test_seq;
last_value | log_cnt | is_called
------------+---------+-----------
1 | 0 | f
(1 row)
4)查看的序列是否被数据库中的其他对象引用
#下面语句要到序列所在的库中执行
select table_catalog,table_schema,table_name,column_name,column_default,data_type from information_schema.columns where column_default ~ 'test_seq';
table_catalog | table_schema | table_name | column_name | column_default | data_type
---------------+--------------+------------+-------------+---------------------------------------+-----------
db_01 | cmp_dac | test_3 | id | nextval('cmp_dac.test_seq'::regclass) | bigint
db_01 | cmp_dac | test_3 | cust_id | nextval('cmp_dac.test_seq'::regclass) | bigint
db_01 | cmp_dac | test_2 | id | nextval('cmp_dac.test_seq'::regclass) | bigint
(3 rows)
四. 序列修改
ALTER SEQUENCE 命令修改一个现有的序列发生器的参数。 任何没有明确在 ALTER SEQUENCE 命令里声明的参数都将保留原先的设置。
要使用 ALTER SEQUENCE,你必须拥有该序列。 要改变一个序列的模式,你必须在新的模式上有 CREATE 权限。要修改所有者,你还必须是新的所有者角色的直接或者间接成员, 并且必须在该序列的模式上具有 CREATE 权限。 (这强制限制在进行更改所有者的操作时,如果无法通过删除后重建序列发生器的方式完成,那么就不能做任何事。不过,超级用户可以改变所有序列发生器的所有者。)
--修改序列语法
ALTER SEQUENCE name [ INCREMENT [ BY ] increment ]
[ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
[ START [ WITH ] start ]
[ RESTART [ [ WITH ] restart ] ]
[ CACHE cache ] [ [ NO ] CYCLE ]
[ OWNED BY { table.column | NONE } ]
ALTER SEQUENCE name OWNER TO new_owner
ALTER SEQUENCE name RENAME TO new_name
ALTER SEQUENCE name SET SCHEMA new_schema
参数
name
一个要修改的序列的名字(可以有模式修饰)。
increment
INCREMENT BY increment 子句是可选的。一个正数会让序列成为递增序列,负数则成为递减序列。 如果没有声明,将沿用原来的递增值。
minvalue
NO MINVALUE
可选的子句 MINVALUE minvalue 决定一个序列可以生成的最小的值。如果声明了 NO MINVALUE,将使用缺省值, 对于递增和递减的序列分别是 1 和 -2^63-1。如果没有声明任何选项,则沿用当前的最小值。
maxvalue
NO MAXVALUE
可选的子句 MAXVALUE maxvalue 决定序列的最大值。如果声明了 NO MAXVALUE,则使用缺省值, 对于递增和递减的序列分别是 2^63-1 和 -1。如果两个选项都没有声明, 则沿用当前的最大值。
start
可选的START WITH start 子句改变序列记录的起始值。当前序列值不受影响,该子句只对后面使用 ALTER SEQUENCE RESTART 命令时使用的值进行设置。
restart
可选的RESTART [ WITH restart ]子句改变序列的当前值。这等效于使用is_called=false参数调用setval函数:设定的值在下一次调用nextval时返回。RESTART 子句如果没有restart值的话,就等效于默认使用 CREATE SEQUENCE 创建序列时记录的起始值或者最后一次使用命令 ALTER SEQUENCE START WITH 设置的起始值。
cache
CACHE cache 选项使能序列号预分配功能,将之存储在内存中加快访问。最小值是 1 (也就是每次只能生成一个数值,没有缓冲)。 如果没有声明,将沿用旧的缓冲值。
CYCLE
可选的键字 CYCLE 可以用于允许序列在达到递增序列的 maxvalue 或者递减序列的 minvalue的时候重叠使用。 如果达到了极限,那么生成的下一个数字将分别是 minvalue 或者 maxvalue。
NO CYCLE
如果指定了可选键字 NO CYCLE,任何在序列达到其最大极限后对 nextval 的调用都将返回错误。 如果既未声明 CYCLE 也未声明 NO CYCLE, 那么将沿用原有的序列号产生方式。
OWNED BY table.column
OWNED BY NONE
OWNED BY 子句将序列与某个表中的列绑定,如此之后如果这个列(或整个表)被删除,序列也将自动被删除。如果设定该子句,之前的绑定都将被替换覆盖。指定的表必须和序列有相同的所有者,并且在一个模式中。OWNED BY NONE子句删除所有已有的绑定,使得序列独立于任何表的列。
new_owner
序列新所有者的用户名。
new_name
序列的新名字。
new_schema
序列的新模式。
注意
为了避免并发的事务从同一个序列获取数值的时候被阻塞住,ALTER SEQUENCE 操作从来不会回滚; 修改马上生效并且不能恢复。但是,OWNED BY, OWNER TO, RENAME TO, 和 SET SCHEMA 子句导致的系统编目的寻常更新可以回滚。
不同于当前后端,ALTER SEQUENCE 命令在其他后端有预分配(已缓冲)的序列号时不会立刻受到影响。它们只有耗尽所有已缓冲的序列值之后才能意识到序列参数的改变。而当前后端将立即被影响。
ALTER SEQUENCE 不影响序列的currval状态。(PostgreSQL8.3之前有时候有影响。)
由于历史原因,ALTER TABLE 也可以用来设置序列;但是ALTER TABLE中那个仅有的用来设置序列的语法形式和上面所示的形式的效果完全相同。
有些 ALTER TABLE 的变种可以和序列一起用; 比如,使用 ALTER TABLE RENAME 给一个序列重命名。
五.?序列常用函数
类型名称 | 返回类型 | 描述 |
---|---|---|
currval(regclass) | bigint | 返回最近一次用nextval获取的指定序列的数值 |
lastval() | bigint | 返回最近一次用nextval获取的任何序列的数值 |
nextval(regclass) | bigint | 递增序列并返回新值 |
setval(regclass, bigint) | bigint | 设置序列的当前数值 |
setval(regclass, bigint, boolean) | bigint | 设置序列的当前数值及is_called标志 |
1)currval(regclass) 函数使用
db_01=# select currval('cmp_dac.test_seq');
ERROR: currval of sequence "test_seq" is not yet defined in this session
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
1
(1 row)
db_01=# select currval('cmp_dac.test_seq');
currval
---------
1
(1 row)
db_01=# select currval('cmp_dac.test_seq');
currval
---------
1
(1 row)
2)lastval()?? ?返回最近一次用nextval获取的任何序列的数值
#lastval函数与currval函数不同,不管最后调用的是哪个序列,总返回当前库最后一次调用的nextval函数的值,不限制序列,只返回最后一次调用的
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
2
(1 row)
db_01=# select nextval('test_seq_1');
nextval
---------
1
(1 row)
db_01=# select lastval();
lastval
---------
1
(1 row)
3)nextval(regclass)?? ?bigint?? ?递增序列并返回新值
nextval函数的参数是regclass,而输入的是一个字符串,这因为regclass类型会自动把字符串转成regclass类型
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
3
(1 row)
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
4
(1 row)
? ?4)setval(regclass, bigint)?? ?bigint?? ?设置序列的当前数值
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
5
(1 row)
db_01=# select setval('cmp_dac.test_seq', 2);
setval
--------
2
(1 row)
^
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
3
(1 row)
5)setval(regclass, bigint, boolean)?? ?bigint?? ?设置序列的当前数值及is_called标志
#三个参数的setval使用时,如果设置了is_called为true,表示下一次的nextval将在返回数值之前递增该序列。如果设置了is_called为false,那么下一次nextval将返回声明的数值,只有再次调用nextval才开始递增该序列。如:
NOTE:注意评估调整序列的起始值,是否会造成数据逻辑错误,或者唯一键冲突等问题
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
4
(1 row)
db_01=# select setval('cmp_dac.test_seq', 2, true);
setval
--------
2
(1 row)
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
3
(1 row)
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
4
(1 row)
db_01=# select setval('cmp_dac.test_seq', 2, false);
setval
--------
2
(1 row)
db_01=# select nextval('cmp_dac.test_seq');
nextval
---------
2
(1 row)