By "disjoint" I mean mutually exclusive sets of ID values. No overlap between both tables.
For example, the sequence generator for the id
column on both tables should work in conjunction to make sure they are always disjoint. I am not sure if this is possible. So, I thought I would just ask here.
Table A
id | name |
---|---|
0 | abc |
1 | cad |
2 | pad |
3 | ial |
Table B
id | name |
---|---|
40 | pal |
50 | sal |
CodePudding user response:
A very simple way is to share the same 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<>fiddle here
This way, table a
"owns" the sequence, while table b
draws from the same source. You can also create an independent SEQUENCE
if you prefer.
Note: this only guarantees mutually exclusive new IDs (even under concurrent write load) while you don't override default values and also don't update them later.
Related:
- Creating a PostgreSQL sequence to a field (which is not the ID of the record)
- Safely rename tables using serial primary key columns
- Auto increment table column
- PostgreSQL next value of the sequences?
CodePudding user response:
Welcome to the painful world of inter-table constraints or assertions - this is something that ISO SQL and pretty much every RDBMS out there does not handle ergonomically...
(While ISO SQL does describe both deferred-constraints and database-wide assertions, as far as I know only PostgreSQL implements deferred-constraints, and no production-quality RDBMS supports database-wide assertions).
One approach is to have a third-table which is the only table with SERIAL
(aka IDENTITY
aka AUTO_INCREMENT
) with a discriminator column which combined forms the table's primary-key, then the other two tables have an FK constraint to that PK - but they'll also need the same discriminator column (enforced with a CHECK
constraint), but you will never need to reference that column in most queries.
As your post doesn't tell us what the real table-names are, I'll use my own.
Something like this:
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 )
)
With this design, it is impossible for any row in shitposts
to share a postId
value with a post in goldposts
and vice-versa.
However it is possible for a row to exist in postIds
without having any row in both goldposts
and shitposts
. Fortunately, as you are using PostgreSQL you could add a new FK constraint from postIds
to both goldposts
and shitposts
but use it with deferred-constraints.
CodePudding user response:
A different hack-around:
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;
Result:
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)