sql >> Database >  >> RDS >> PostgreSQL

Compact of hernummer ID's voor alle tabellen, en reset reeksen naar max(id)?

De vraag is oud, maar we kregen een nieuwe vraag van een wanhopige gebruiker op dba.SE nadat we hadden geprobeerd toe te passen wat hier wordt voorgesteld. Vind een antwoord met meer details en uitleg daar :

Het momenteel geaccepteerde antwoord zal in de meeste gevallen mislukken .

  • Meestal heb je een PRIMARY KEY of UNIQUE beperking op een id kolom, die NOT DEFERRABLE . is standaard. (OP vermeldt references and constraints .) Dergelijke beperkingen worden na elke rij gecontroleerd, dus u krijgt hoogstwaarschijnlijk een unieke overtreding fouten proberen. Details:

  • Meestal wil men de originele volgorde van rijen . behouden terwijl gaten worden gedicht. Maar de volgorde waarin rijen worden bijgewerkt is willekeurig , wat leidt tot willekeurige getallen. Het gedemonstreerde voorbeeld lijkt de oorspronkelijke volgorde te behouden omdat fysieke opslag nog steeds samenvalt met de gewenste volgorde (rijen in de gewenste volgorde een moment eerder ingevoegd), wat bijna nooit het geval is in toepassingen in de echte wereld en volledig onbetrouwbaar.

De zaak is ingewikkelder dan het op het eerste gezicht lijkt. Eén oplossing (onder andere) als u het zich kunt veroorloven om de PK / UNIQUE-beperking (en gerelateerde FK-beperkingen) tijdelijk te verwijderen:

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;

Dit is ook veel sneller voor grote tabellen, omdat het controleren van PK (en FK)-beperkingen voor elke rij veel meer kost dan het verwijderen van de beperking(en) en het opnieuw toevoegen ervan.

Als er FK-kolommen in andere tabellen zijn die verwijzen naar tbl.id , gebruik gegevensmodificerende CTE's om ze allemaal bij te werken.

Voorbeeld voor een tabel fk_tbl en een FK-kolom 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

Meer in het verwezen antwoord op dba.SE .



  1. Awesome 24 Concurrent Manager Sollicitatievragen

  2. Hoe kun je zien of een waarde niet numeriek is in Oracle?

  3. MYSQL-subsetbewerking

  4. Controleren op datumbereikconflicten in MySQL