Possible to condense primary key/serial?

前端 未结 4 1123
挽巷
挽巷 2021-01-21 19:56

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.

4条回答
  •  说谎
    说谎 (楼主)
    2021-01-21 20:09

    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

提交回复
热议问题