Possible to condense primary key/serial?

半城伤御伤魂 提交于 2019-12-02 03:55:03

问题


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 to id
  • re-create foreign key constraints
  • commit


来源:https://stackoverflow.com/questions/2298841/possible-to-condense-primary-key-serial

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!