PostgreSQL PG序列 与 序列是否可以绑定到多个表的疑问

本文介绍了PostgreSQL中的序列机制,包括序列的创建、使用方法及与Oracle序列的区别。探讨了序列的类型、范围、循环使用等特性,并通过实例展示了序列与表的关系及常见问题。

最近有点累,想休息几天,散散心,下一次更新在周五。

POSTGRESQL 表的自增类似ORACLE 的做法, 当然这不是说就是一样,只是类似.  PostgreSQL的序列本身是需要创建的类似于一个数字序列的生成器,表中字段需要通过设置来获取序列给出的值, one by one .

select c.relname FROM pg_class c WHERE c.relkind = 'S';

通过pg_class 来对我们当前的数据库中的序列进行查找

与Oracle 不同的是PostgreSQL 的基本对于序列的使用是一个表一个序列的方式.

这里对于POSTGRESQL 创建序列有几个需要了解和知道的地方

1  postgresql 的序列是可以有类型的

2  postgresql 的学是有range的,也就是可以设置最大和最小的值

3  postgresql 的序列是可以循环使用的达到了最大值后,如果设置了循环是可以从头开始的

4  cache 这个是PG对于自增序列的一个友好和快速数据分配和插入的支持,我们可以

create sequence id_seq as bigint increment 1 minvalue 100 NO MAXVALUE start 100 cache 1000 cycle;

owner by  主要是将自增与数据库表的列建立关系,如果这列删除则自增也会被删除.

创建一个表

create table seq (id int primary key, name varchar(10));

alter sequence id_seq owned by  seq.id;

把刚才建立的序列挂载到表中.通过 nextval 函数来调用序列.

由于我们之前设置的初始值是100 所以这边通过nextval 的第一个值是100

select * from pg_sequences;

并且通过pg_sequences 来查看当前的schema中的所有的sequence 的信息,这点其实比ORACLE 的sequences 要好(11G).

如果在使用序列的时候需要获得序列的select currval('id_seq');  当前的已经使用的最后一个值,类似有些数据库的last value .

另外还有一些常见的问题

1   我truncate 表后, 序列有变化吗?

2   我可以多个表绑定一个序列吗

3   我删除数据后,序列会有变化吗

4   我事务得到分配的序列值后,如果回滚了我的序列值应该在那个位置?

truncate 表后,并没有讲序列的值进行任何改变,在此插入数据库还是会继续累加上一次的值.

说完这些其实就有一个问题了, ORACLE 当中的序列是可以一个序列绑定到多个表的上来进行序列的值的给出. 那么POSTGRESQL 本身是不是可以这样做,我们来实验一下.

我产生一个序列,通过这个序列绑定 几个表看看情况如何

create sequence id_seq as bigint increment 1 minvalue 100 NO MAXVALUE start 100 cache 1000 cycle;

 create table seq (id int primary key, name varchar(10));

alter sequence id_seq owned by  seq.id

insert into seq (id,name) values (nextval('id_seq'),'1');

select * from seq;

 create table seq2 (id int primary key, name varchar(10));

 create table seq3 (id int primary key, name varchar(10));

alter sequence id_seq owned by  seq2.id;

insert into seq2 (id,name) values (nextval('id_seq'),'1');

select * from seq2;

alter sequence id_seq owned by  seq3.id;

insert into seq3 (id,name) values (nextval('id_seq'),'1');

select * from seq3;

从上面的测试看,我们的可以明显的看到一个问题,如果一个序列挂多个表,则对于序列来说,是顺序性的,并不能做到一个序列分别对每个表进行分别的计数.

而上面的明显的在绑定第二个表后,插入数变为了1100 的主要的原因是cache ,cache 中设置的数字决定了你绑定下一个表的基数,也就是插入数据后第一个数据起始值.

如 cache 是1000 , 则第一个表当前的插入值是  100, 我们在绑定第二个表后,在此插入值是 1100, 而在绑定第三个表,插入值是 2100. 

所以POSTGRESQL 本身的序列 sequense 只能一个序列一个表使用,不建议多个表使用一个序列.

<think>我们之前讨论过,重新绑定序列后,使用`pg_get_serial_sequence`函数查询依然无值。这通常是由于列的默认值设置不正确,或者序列绑定关系未正确建立。下面我们来详细分析原因并提供解决方案。 ### 问题分析 1. **函数依赖原理** `pg_get_serial_sequence(table_name, column_name)`函数通过以下方式工作: - 检查列的默认值达式是否为`nextval('seq_name'::regclass)`形式 - 验证该序列是否被标记为“属于”该列(通过`pg_depend`系统目录) 2. **重建序列后无值的常见原因** - **原因1:默认值绑定错误** 使用`ALTER TABLE ... ALTER COLUMN SET DEFAULT ...`时序列名错误 - **原因2:未设置序列所有权** 缺少`ALTER SEQUENCE ... OWNED BY ...`操作 - **原因3:系统缓存未更新** PostgreSQL的系统目录缓存未及时刷新 ### 解决方案 #### 步骤1:验证默认值设置 执行以下查询确认默认值达式: ```sql SELECT column_default FROM information_schema.columns WHERE table_name = 't_sys_org' AND column_name = 'id'; ``` 期望结果应包含类似: ```sql nextval('t_sys_org_id_seq'::regclass) ``` 若不符合: ```sql -- 修复默认值(替换为实际序列名) ALTER TABLE t_sys_org ALTER COLUMN id SET DEFAULT nextval('t_sys_org_id_seq'); ``` #### 步骤2:建立序列所有权 ```sql -- 将序列标记为属于该列 ALTER SEQUENCE t_sys_org_id_seq OWNED BY t_sys_org.id; ``` > **所有权验证**: > ```sql > SELECT seq.relname AS sequence, > dep.refobjid::regclass AS owned_table, > dep.refobjsubid AS owned_column > FROM pg_class seq > JOIN pg_depend dep ON seq.oid = dep.objid > WHERE seq.relkind = 'S' > AND seq.relname = 't_sys_org_id_seq'; > ``` > 应返回`t_sys_org`和`id`列信息 #### 步骤3:刷新系统目录(如缓存问题) ```sql -- 强制刷新系统目录(需超级用户权限) REINDEX SYSTEM postgres; ``` > 无超级用户权限时重启PostgreSQL服务也可达到同样效果 #### 步骤4:最终验证 ```sql SELECT pg_get_serial_sequence('t_sys_org', 'id'); ``` 预期返回:`public.t_sys_org_id_seq` ### 特殊情况处理 #### 情况1:跨模式(schema)序列序列在其他模式中: ```sql -- 显式指定模式路径 ALTER TABLE t_sys_org ALTER COLUMN id SET DEFAULT other_schema.t_sys_org_id_seq.nextval; -- 更新所有权(需在序列所在模式操作) ALTER SEQUENCE other_schema.t_sys_org_id_seq OWNED BY public.t_sys_org.id; ``` #### 情况2:列被定义为GENERATED ALWAYS AS IDENTITY PostgreSQL 10+版本使用新标准语法: ```sql -- 创建示例 CREATE TABLE t_sys_org ( id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY ); -- 修复需重建标识列 ALTER TABLE t_sys_org ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY; ``` ### 操作流程图 ```mermaid graph TD A[问题:pg_get_serial_sequence返回空] --> B{检查默认值} B -->|错误/缺失| C[设置DEFAULT nextval] B -->|正确| D{检查序列所有权} D -->|未设置| E[执行ALTER SEQUENCE OWNED BY] D -->|已设置| F{检查缓存} F -->|疑似缓存问题| G[REINDEX SYSTEM或重启] F -->|正常| H[验证成功] ``` §§相关问题§§ 1. 如何批量修复数据库中所有序列关联问题? 2. 序列丢失所有权会导致什么后果? 3. PostgreSQL的`pg_depend`系统目录有哪些关键字段? 4. `GENERATED AS IDENTITY``SERIAL`在底层实现上有何区别? 5. 如何安全地修改正在使用的序列参数(如START WITH)? 通过以上步骤,99%的序列绑定问题都能解决。若仍无效,可能是更深的系统目录损坏,需考虑`pg_dump`导出后重建数据库。 </think>### 重新绑定序列后`pg_get_serial_sequence`无值的解决方法 重新绑定序列后`pg_get_serial_sequence`仍返回空值,通常由三个核心问题引起。以下是系统排查和解决方案: #### 一、核心修复步骤 1. **验证序列所有权关系** 执行以下命令确认序列所有权: ```sql SELECT seq.relname, dep.refobjid::regclass AS owned_table FROM pg_class seq JOIN pg_depend dep ON seq.oid = dep.objid WHERE seq.relkind = 'S' AND seq.relname = 't_sys_org_id_seq'; -- 替换为实际序列名 ``` **修复命令**: ```sql ALTER SEQUENCE t_sys_org_id_seq OWNED BY t_sys_org.id; ``` 2. **刷新系统目录缓存** PostgreSQL可能缓存旧元数据: ```sql -- 方法1:重启PostgreSQL服务 sudo systemctl restart postgresql -- 方法2:强制刷新(需超级用户) REINDEX TABLE t_sys_org; ``` 3. **修复默认值达式** 确保默认值使用`regclass`类型转换: ```sql ALTER TABLE t_sys_org ALTER COLUMN id SET DEFAULT nextval('t_sys_org_id_seq'::regclass); ``` #### 二、特殊场景解决方案 **场景1:跨模式(Schema)序列** 当序列在不同模式时: ```sql -- 显式指定模式路径 SELECT pg_get_serial_sequence('public.t_sys_org', 'id'); -- 修复默认值 ALTER TABLE t_sys_org ALTER COLUMN id SET DEFAULT nextval('other_schema.t_sys_org_id_seq'::regclass); ``` **场景2:`GENERATED AS IDENTITY`列** PostgreSQL 10+ 使用新标准: ```sql -- 检查列定义 SELECT is_identity, identity_generation FROM information_schema.columns WHERE table_name = 't_sys_org'; -- 重建标识列 ALTER TABLE t_sys_org ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY; ``` #### 三、深度诊断工具 ```sql -- 检查系统目录关联 SELECT c.oid::regclass AS table_name, a.attname AS column_name, s.relname AS sequence_name, d.refobjid::regclass AS owned_by FROM pg_attribute a JOIN pg_class c ON a.attrelid = c.oid LEFT JOIN pg_depend d ON d.objid = a.attrelid AND d.refobjsubid = a.attnum LEFT JOIN pg_class s ON s.oid = d.refobjid WHERE c.relname = 't_sys_org' AND a.attname = 'id'; ``` **预期输出**: ``` table_name | column_name | sequence_name | owned_by ------------|-------------|-------------------|---------- t_sys_org | id | t_sys_org_id_seq | t_sys_org ``` #### 四、操作验证流程 ```mermaid graph LR A[执行修复操作] --> B{查询pg_get_serial_sequence} B -->|返回NULL| C[检查序列所有权] C -->|缺失| D[ALTER SEQUENCE OWNED BY] C -->|存在| E[检查默认值达式] E -->|无::regclass| F[添加类型转换] E -->|正确| G[刷新系统目录] G -->|成功| H[验证通过] ``` > **关键原理**:`pg_get_serial_sequence`依赖于`pg_depend`系统目录和默认值达式的精确匹配[^1]。所有权关系缺失或达式格式错误均会导致失败。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值