PostgreSQL中如何让继承表共享自增ID列?
PostgreSQL继承表共享唯一ID失败及插入报错解决
背景与问题
表结构
CREATE TABLE A ( ID integer PRIMARY KEY generated always as identity, data integer ); CREATE TABLE B ( other_data integer ) INHERITS (A); CREATE TABLE C ( other_other_data integer ) INHERITS (A);
需求
要让表B和C的ID字段全局唯一,两张表的ID不重复。
报错场景
执行插入语句:
insert into B (other_data) values (1)
触发错误:
ERROR: null value in column "id" of relation "B" violates not-null constraint DETAIL: Failing row contains (null)
你怀疑继承方式没法实现共享唯一ID,另外之前长期用serial类型,后来才在维基看到不推荐的警告,还觉得PostgreSQL文档体验不好。
问题原因
PostgreSQL的表继承机制里,父表的identity列不会自动把序列传递给子表。子表虽然继承了ID列的非空、主键约束,但没继承自增序列的默认值,所以插入时ID字段没有值,触发非空约束报错。
解决办法
方法1:用全局共享序列
放弃父表的identity定义,手动创建一个全局序列,让所有表的ID都用这个序列生成:
- 创建全局序列:
CREATE SEQUENCE global_id_seq;
- 重新创建父表A:
CREATE TABLE A ( ID integer PRIMARY KEY DEFAULT nextval('global_id_seq'), data integer );
- 子表B、C的继承定义不变,插入时会自动从全局序列取ID,自然保证B和C的ID不重复:
INSERT INTO B (other_data) VALUES (1); INSERT INTO C (other_other_data) VALUES (2);
方法2:用UUID(适合不需要自增的场景)
如果不需要整数自增ID,用UUID可以天然实现全局唯一:
- 先启用UUID扩展:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
- 定义父表:
CREATE TABLE A ( ID uuid PRIMARY KEY DEFAULT uuid_generate_v4(), data integer );
- 子表继承后,插入时会自动生成唯一UUID,不需要额外处理。
关于serial类型
serial是PostgreSQL早期的语法糖,本质是自动创建序列+给列加默认值,但序列和列的关联松散,删除列时序列不会自动清理;而generated always as identity是SQL标准语法,关联更严谨,所以官方推荐用后者替代serial。
内容的提问来源于stack exchange,提问作者Dorknob78
相关产品推荐
相关产品推荐

