Можно ли сжать первичный ключ / серийный номер? - PullRequest
2 голосов
/ 19 февраля 2010

У меня есть база данных, где все связано с внешними ключами, поэтому Postgres точно знает, как устроена база данных.

Хорошо, допустим, у меня есть Таблица1 и Таблица2.

Таблица1 имеет 3 поля. RID, table2_rid, data

Таким образом, table1.table2_rid ссылается на table2.RID, и это выражается внешним ключом. В обоих полях RID указан первичный ключ и серийный тип.

Что я хотел бы знать, так это как «сжать» первичные ключи? Например, вы добавили 5 записей и удалили номер записи 3. Ваши первичные ключи будут выглядеть так:

1
2
4
5 

Хорошо, как мне получить обновление везде, чтобы первичный ключ (и соответствующие внешние ключи) можно было сжать в

1
2
3
4

Ответы [ 4 ]

2 голосов
/ 19 февраля 2010

Лучше, если первичный ключ никогда не изменится: нумерация их - это PITA.

Если вам нужен идентификатор для человека, без пробелов, А. Элейн Мустейн показывает , как создать последовательность без пробелов .

1 голос
/ 21 октября 2012

Вы, вероятно, не хотите делать это вообще, так как последовательности без пробелов проблематичны для производительности .

Если вы хотите сделать это в качестве шага очистки позже, вы можете использовать rank() оконная функция для достижения желаемого эффекта.

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;

Результат:

regress=# select * from table1 ;
 id 
----
  1
  2
  3
  4
(4 rows)

Если ваши ФК не ON UPDATE CASCADE, вы можете ALTER TABLE сделать их так.Это будет довольно медленно, особенно если на внешних ключах нет индексов.Более быстрый подход состоит в том, чтобы выполнить изменение в два прохода:

  • Начать транзакцию
  • LOCK TABLE table1;
  • Добавить столбец new_id в table1 и заполнить егоновые идентификаторы, использующие row_number(), как показано выше
  • Удаление ограничений внешнего ключа, ссылающихся на table1 (id)
  • Обновление всех внешних ключей для ссылки на значения в new_id
  • drop id в table1
  • переименовать столбец new_id таблицы1 в id
  • заново создать ограничения внешнего ключа
  • commit
1 голос
/ 19 февраля 2010

За исключением очень редких сценариев, пропуски в последовательности PK являются правильными, и намерение избавиться от них - плохая идея.

1 голос
/ 19 февраля 2010

Посмотрите на on update cascade и 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)
);
...