PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Skondensować lub zmienić numerację identyfikatorów dla wszystkich tabel i zresetować sekwencje do max(id)?

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 KEY lub UNIQUE ograniczenie na id kolumna, która jest NOT DEFERRABLE domyślnie. (OP wspomina o references 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 .



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Problem z sortowaniem Postgres

  2. Wiele baz danych w docker i docker-compose

  3. Postgre SQL ignoruje warunek filtrowania, jeśli wartość ma wartość null

  4. Jak uzyskać czas tworzenia bazy danych w PostgreSQL 9.0?

  5. jak zwrócić tabelę temp z funkcji postgres?