问题
I have a database where everything is linked with foreign keys, so the Postgres knows exactly how the database is layed out..
Well, Lets say I have Table1 and Table2.
Table1 has 3 fields. RID, table2_rid,data
So table1.table2_rid references table2.RID and this is expressed with a foreign key. In both the RID
field is the primary key and is a serial type.
What I would like to know is how to "condense" the primary keys? Like say you add 5 records and deleted record number 3. Your primary keys would look like
1
2
4
5
Well, how do I get to update everywhere so that the primary key(and corresponding foreign keys) can be condensed into
1
2
3
4
回答1:
It's best if a primary key never changes: Renumbering them is a PITA.
If you need an ID for humans, one that has no gaps, A. Elein Mustain shows how to create a gapless sequence.
回答2:
Look into on update cascade
and on delete cascade
.
create table table_1 (
id integer
primary key,
name char(30)
);
create table table_2 (
id integer
primary key,
table_1_id integer
references table_1
on update cascade
on delete cascade,
detail char(30)
);
回答3:
Except for very rare scenarios, gaps in the PK sequence are just right, to intent to get rid of them is a bad idea.
回答4:
You probably don't want to do this generally, as gapless sequences are problematic for performance.
If you want to do it as a cleanup step later you can use the rank()
window function to achieve the desired effect.
CREATE TABLE table1 (id integer primary key);
INSERT INTO table1 values (1),(2),(4),(5);
CREATE TABLE table2 (
id serial primary key,
rid integer references table1(id) ON UPDATE CASCADE
);
insert into table2 (rid) values (1),(1),(4),(4),(4),(5);
UPDATE table1
SET id = gapless_id
FROM (
SELECT *, row_number() OVER () FROM table1
) AS x(old_id, gapless_id)
WHERE id = x.old_id;
Result:
regress=# select * from table1 ;
id
----
1
2
3
4
(4 rows)
If your FK's aren't ON UPDATE CASCADE
you can ALTER TABLE
to make them so. This will be quite slow though, especially if there are no indexes on the foreign keys. A faster approach is to do the change in two passes:
- Begin a transaction
LOCK TABLE table1;
- Add a new_id column to table1 and populate it with the new IDs using
row_number()
as shown above - Drop foreign key constraints referring to table1(id)
- Update all foreign keys to refer to the values in
new_id
- drop
id
in table1 - rename the
new_id
column of table1 toid
- re-create foreign key constraints
- commit
来源:https://stackoverflow.com/questions/2298841/possible-to-condense-primary-key-serial