sql >> Databasteknik >  >> RDS >> PostgreSQL

Kompakta eller numrera om ID:n för alla tabeller och återställa sekvenser till max(id)?

Frågan är gammal, men vi fick en ny fråga från en desperat användare på dba.SE efter att ha försökt tillämpa det som föreslås här. Hitta ett svar med mer information och förklaring där :

Det för närvarande accepterade svaret misslyckas i de flesta fall .

  • Vanligtvis har du en PRIMARY KEY eller UNIQUE begränsning på ett id kolumn, som är NOT DEFERRABLE som standard. (OP nämner references and constraints .) Sådana begränsningar kontrolleras efter varje rad, så du får med största sannolikhet unik överträdelse fel vid försök. Detaljer:

  • Vanligtvis vill man behålla den ursprungliga ordningen av rader samtidigt som man täpper till luckor. Men ordningen i vilken rader uppdateras är godtycklig , vilket leder till godtyckliga siffror. Det visade exemplet verkar behålla den ursprungliga sekvensen eftersom fysisk lagring fortfarande sammanfaller med den önskade ordningen (infogade rader i önskad ordning bara ett ögonblick tidigare), vilket nästan aldrig är fallet i verkliga tillämpningar och helt opålitligt.

Saken är mer komplicerad än den kan tyckas först. En lösning (bland annat) om du har råd att ta bort PK/UNIKA-begränsningen (och relaterade FK-begränsningar) tillfälligt:

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;

Detta är också mycket snabbare för stora tabeller, eftersom att kontrollera PK (och FK) begränsning(ar) för varje rad kostar mycket mer än att ta bort begränsningen(erna) och lägga till den (dem) tillbaka.

Om det finns FK-kolumner i andra tabeller som hänvisar till tbl.id , använd datamodifierande CTE:er för att uppdatera dem alla.

Exempel på en tabell fk_tbl och en FK-kolumn 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

Mer i referat svar på dba.SE .



  1. Vad är datumtypen i npgsql?

  2. I Oracle, när det gäller syntax - hur konverterar jag (+)-syntaxen till modern konventionell JOIN?

  3. .sql-filen returnerar inte kolumnrubriken i csv-filen

  4. får fel ORA-00907 när du skapar en tabell i sql-utvecklaren