By "disjoint"我指的是相互排斥的ID值集合。两个表之间没有重叠。
例如,两个表上id
列的序列生成器应该一起工作,以确保它们总是不相交的。我不确定这是否可能。所以,我想我就在这里问一下。
表
另一种破解方法:
CREATE TABLE odd(
id INTEGER GENERATED ALWAYS AS IDENTITY (START 1 INCREMENT 2)
, val integer
);
CREATE TABLE even(
id INTEGER GENERATED ALWAYS AS IDENTITY (START 2 INCREMENT 2)
, val integer
);
INSERT INTO odd (val)
SELECT GENERATE_SERIES(1,10);
INSERT INTO even (val)
SELECT GENERATE_SERIES(1,20);
SELECT * FROM odd;
SELECT * FROM even;
结果:
CREATE TABLE
CREATE TABLE
INSERT 0 10
INSERT 0 20
id | val
----+-----
1 | 1
3 | 2
5 | 3
7 | 4
9 | 5
11 | 6
13 | 7
15 | 8
17 | 9
19 | 10
(10 rows)
id | val
----+-----
2 | 1
4 | 2
6 | 3
8 | 4
10 | 5
12 | 6
14 | 7
16 | 8
18 | 9
20 | 10
22 | 11
24 | 12
26 | 13
28 | 14
30 | 15
32 | 16
34 | 17
36 | 18
38 | 19
40 | 20
(20 rows)
一个非常简单的方法是共享相同的SEQUENCE
:
CREATE TABLE a (
id serial PRIMARY KEY
, name text
);
CREATE TABLE b (
id int PRIMARY KEY
, name text
);
SELECT pg_get_serial_sequence('a', 'id'); -- 'public.a_id_seq'
ALTER TABLE b ALTER COLUMN id SET DEFAULT nextval('public.a_id_seq'); -- !
db<此处小提琴>此处小提琴>
这样表a
"owns"序列,而表b
从相同的来源提取。如果你愿意,你也可以创建一个独立的SEQUENCE
。
注意:只这保证互斥的新id(即使在并发写负载下),同时不重写默认值,以后也不更新它们。
相关:
- 创建一个PostgreSQL序列到一个字段(不是记录的ID)
- 使用串行主键列安全地重命名表
- 自动递增表列
- PostgreSQL下一个序列的值?
欢迎来到表间约束或断言的痛苦世界-这是ISO SQL和几乎所有RDBMS都无法从人体工程学角度处理的事情…
(虽然ISO SQL确实描述了延迟约束和数据库范围的断言,但据我所知,只有PostgreSQL实现了延迟约束,没有生产质量的RDBMS支持数据库范围的断言)
一种方法是有第三个表,它是只有表与SERIAL
(又名IDENTITY
又名AUTO_INCREMENT
)的一个鉴别符列,结合形成表的主键,然后其他两个表有一个FK约束PK -但他们也需要相同的鉴别符列(与CHECK
约束强制),但你永远不需要在大多数查询引用该列。
由于你的文章没有告诉我们真正的表名是什么,我将使用我自己的
像这样:
CREATE TABLE postIds (
postId int NOT NULL SERIAL,
postType char(1) NOT NULL, /* This is the discriminator column. It can only contain ONLY either 'S' or 'G' which indicates which table contains the rest of the data */
CONSTRAINT PK_postIds PRIMARY KEY ( postId, postType ),
CONSTRAINT CK_type CHECK ( postType IN ( 'S', 'G' ) )
);
CREATE TABLE shitposts (
postId int NOT NULL,
postType char(1) DEFAULT('S'),
foobar nvarchar(255) NULL,
etc int NOT NULL,
CONSTRAINT PK_shitpostIds PRIMARY KEY ( postId, postType ),
CONSTRAINT CK_type CHECK ( postType = 'S' ),
CONSTRAINT FK_shitpost_ids FOREIGN KEY ( postId, postType ) REFERENCES postIds ( postId, postType )
);
CREATE TABLE goldposts (
postId int NOT NULL,
postType char(1) DEFAULT('G'),
foobar nvarchar(255) NULL,
etc int NOT NULL,
CONSTRAINT PK_goldpostIds PRIMARY KEY ( postId, postType ),
CONSTRAINT CK_type CHECK ( postType = 'G' ),
CONSTRAINT FK_goldpost_ids FOREIGN KEY ( postId, postType ) REFERENCES postIds ( postId, postType )
)
使用这种设计,shitposts
中的任何行都不可能与goldposts
中的帖子共享postId
值,反之亦然。
然而,可以在postIds
中存在一行,而不需要在goldposts
和shitposts
中都有任何行。幸运的是,当你使用PostgreSQL时,你可以从postIds
添加一个新的FK约束到goldposts
和shitposts
,但是使用延迟约束。