PostgreSQL数据库序列的DDL获取和细节处理

看腻了就来听听视频演示吧:
SQL拼接获取DDL:https://www.bilibili.com/video/BV1Rw4m1Z7SV/
dump方式获取DDL:https://www.bilibili.com/video/BV1Wt421b75Q/

创建测试数据

-- 创建serial字段类型的表,序列和表有强关联关系
drop table if exists t_serial;
create table t_serial(col1 serial,col2 varchar(60));
insert into t_serial (col2) select md5(random()::text) from generate_series(1,10);
-- 直接创建序列使用,表的default默认值设置为序列值,序列和表并无强关联关系
drop table if exists t_test;
drop SEQUENCE if exists t_test_id_seq;
CREATE SEQUENCE t_test_id_seq START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;
create table t_test(id int,name varchar(80));
alter table t_test alter COLUMN id set not null;
alter table t_test alter COLUMN id set default nextval('t_test_id_seq'::regclass);
insert into t_test (name) select md5(random()::text) from generate_series(1,10);

dump导出方式

把库和创建的表导出来看看情况:

-- 单库导出:CREATE TABLE -> CREATE SEQUENCE -> COPY -> setval
pg_dump testdb -f db_testdb_all.sql 
-- 单库仅导出DDL:1)serial:CREATE TABLE -> CREATE SEQUENCE 2)手动创建的序列:CREATE SEQUENCE -> CREATE TABLE 【没COPY导数据过程忽略setval步骤】
pg_dump testdb -s -f db_testdb_ddl.sql 
-- 导出serial类型的表:CREATE TABLE -> CREATE SEQUENCE -> COPY -> setval
pg_dump testdb -t public.t_serial -f tbl_t_serial.sql 
-- 导出手动创建序列使用的表:CREATE TABLE -> COPY 【默认序列已存在,不会导出序列】
pg_dump testdb -t public.t_test -f tbl_t_test.sql 

表列与序列强关联

pg_get_serial_sequence 返回与列关联的序列名

-- select pg_get_serial_sequence('表名','列名');
21:00:13 muser@testdb=> \df pg_get_serial_sequence 
                                  List of functions
   Schema   |          Name          | Result data type | Argument data types | Type 
------------+------------------------+------------------+---------------------+------
 pg_catalog | pg_get_serial_sequence | text             | text, text          | func
(1 row)

21:00:53 muser@testdb=> select pg_get_serial_sequence('t_serial','col1');
  pg_get_serial_sequence  
--------------------------
 public.t_serial_col1_seq
(1 row)

-- 手动创建的序列不会与表关联
21:01:01 muser@testdb=> select pg_get_serial_sequence('t_test','id');
 pg_get_serial_sequence 
------------------------
 
(1 row)
-- 调整序列为表列的所有者即关联序列后即可查询到,等效于serial类型
21:05:53 muser@testdb=> alter sequence t_test_id_seq owned by t_test.id;
ALTER SEQUENCE
21:06:15 muser@testdb=> select pg_get_serial_sequence('t_test','id');
 pg_get_serial_sequence 
------------------------
 public.t_test_id_seq
(1 row)

调整序列为表列的所有者后即等效于serial类型,dump导出效果也是一样的。

case场景

遇到一个需求:业务要当前使用的序列DDL,上面dump出来的数据就存在两个问题:
1). 单库或模式导出DDL的序列创建语句START WITH的值为下面视图的start_value,而非当前currval的值,即last_value。这就会出现序列重复冲突的问题
2). 单库包括数据一起导出,即CREATE TABLE -> CREATE SEQUENCE -> COPY -> setval,然后再过滤CREATE和setval语句。可满足需求但当数据量较大会使过滤文件耗时较长

image.png

记录序列的视图:

17:10:25 muser@testdb=> \d+ pg_sequences
                          View "pg_catalog.pg_sequences"
    Column     |  Type   | Collation | Nullable | Default | Storage | Description 
---------------+---------+-----------+----------+---------+---------+-------------
 schemaname    | name    |           |          |         | plain   | 
 sequencename  | name    |           |          |         | plain   | 
 sequenceowner | name    |           |          |         | plain   | 
 data_type     | regtype |           |          |         | plain   | 
 start_value   | bigint  |           |          |         | plain   | 
 min_value     | bigint  |           |          |         | plain   | 
 max_value     | bigint  |           |          |         | plain   | 
 increment_by  | bigint  |           |          |         | plain   | 
 cycle         | boolean |           |          |         | plain   | 
 cache_size    | bigint  |           |          |         | plain   | 
 last_value    | bigint  |           |          |         | plain   | 
View definition:
 SELECT n.nspname AS schemaname,
    c.relname AS sequencename,
    pg_get_userbyid(c.relowner) AS sequenceowner,
    s.seqtypid::regtype AS data_type,
    s.seqstart AS start_value,
    s.seqmin AS min_value,
    s.seqmax AS max_value,
    s.seqincrement AS increment_by,
    s.seqcycle AS cycle,
    s.seqcache AS cache_size,
        CASE
            WHEN has_sequence_privilege(c.oid, 'SELECT,USAGE'::text) THEN pg_sequence_last_value(c.oid::regclass)
            ELSE NULL::bigint
        END AS last_value
   FROM pg_sequence s
     JOIN pg_class c ON c.oid = s.seqrelid
     LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
  WHERE NOT pg_is_other_temp_schema(n.oid) AND c.relkind = 'S'::"char";

序列DDL拼接SQL语句

这里我们可以根据序列记录的视图来拼接下序列的DDL

-- 拼接public模式下的序列DDL
select 'create sequence ' || a.schemaname || '.' || a.sequencename || ' INCREMENT BY ' || a.increment_by || ' START WITH ' || a.last_value+1 || ' MAXVALUE ' || a.max_value || 
        case when a.cycle='t' then ' CYCLE' else ' NOCYCLE' end ||
        case when a.cache_size=1 then ' nocache' else ' cache ' || cache_size end || ';'
from pg_sequences a where a.schemaname='public';

这里拼接的序列DDL还有个小问题:新创建的序列last_value列值为null,需要先手动执行下nextval后才能搜索到
image.png

于是先拼接下last_value值为null的序列手动执行下

select 'select nextval(''' || a.schemaname || '.' || a.sequencename || '''::regclass)' || ';' from pg_sequences a where a.last_value is null;

image.png

序列删除情况

删除表时序列的情况

  • 序列和表有强关联关系:serial类型或调整过序列为表列的所有者即关联序列的情况,删除表对应序列会一起被删除
  • 序列和表无强关联关系:删除表对序列不影响

屏幕快照 20240224 10.59.13.png

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值