Pytanie jest stare, ale otrzymaliśmy nowe pytanie od zdesperowanego użytkownika dba.SE po próbie zastosowania sugestii tutaj. Znajdź odpowiedź z więcej szczegółów i wyjaśnień tam :
obecnie zaakceptowana odpowiedź zawiedzie w większości przypadków .
-
Zazwyczaj masz
PRIMARY KEYlubUNIQUEograniczenie naidkolumna, która jestNOT DEFERRABLEdomyślnie. (OP wspomina oreferences and constraints.) Takie ograniczenia są sprawdzane po każdym wierszu, więc najprawdopodobniej otrzymasz unikalne naruszenie błędy próbujące. Szczegóły: -
Zazwyczaj chce się zachować pierwotną kolejność wierszy jednocześnie zamykając luki. Ale kolejność, w jakiej wiersze są aktualizowane, jest dowolna , co prowadzi do dowolnych liczb. Zademonstrowany przykład wydaje się zachowywać pierwotną kolejność, ponieważ fizyczne przechowywanie nadal pokrywa się z pożądaną kolejnością (wiersze zostały wstawione w żądanej kolejności chwilę wcześniej), co prawie nigdy nie ma miejsca w rzeczywistych zastosowaniach i jest całkowicie zawodne.
Sprawa jest bardziej skomplikowana, niż mogłoby się początkowo wydawać. Jeden rozwiązanie (między innymi), jeśli możesz sobie pozwolić na tymczasowe usunięcie ograniczenia PK / UNIQUE (i powiązanych ograniczeń FK):
BEGIN;
LOCK tbl;
-- remove all FK constraints to the column
ALTER TABLE tbl DROP CONSTRAINT tbl_pkey; -- remove PK
-- for the simple case without FK references - or see below:
UPDATE tbl t -- intermediate unique violations are ignored now
SET id = t1.new_id
FROM (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
WHERE t.id = t1.id;
-- Update referencing value in FK columns at the same time (if any)
SELECT setval('tbl_id_seq', max(id)) FROM tbl; -- reset sequence
ALTER TABLE tbl ADD CONSTRAINT tbl_pkey PRIMARY KEY(id); -- add PK back
-- add all FK constraints to the column back
COMMIT;
To też dużo szybciej w przypadku dużych tabel, ponieważ sprawdzenie ograniczeń PK (i FK) dla każdego wiersza kosztuje znacznie więcej niż usunięcie ograniczeń i dodanie ich z powrotem.
Jeśli w innych tabelach istnieją kolumny FK odwołujące się do tbl.id , użyj CTE modyfikacji danych aby zaktualizować je wszystkie.
Przykład tabeli fk_tbl i kolumna FK fk_id :
WITH u1 AS (
UPDATE tbl t
SET id = t1.new_id
FROM (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
WHERE t.id = t1.id
RETURNING t.id, t1.new_id -- return old and new ID
)
UPDATE fk_tbl f
SET fk_id = u1.new_id -- set to new ID
FROM u1
WHERE f.fk_id = u1.id; -- match on old ID
Więcej w odpowiedzi na dba.SE .