2016-04-09 2 views
0

Ich migrierte eine alte MySQL-Datenbank zu postgresql. Nach dem ganzen Prozess, und Einfügen der Daten habe ich herausgefunden, dass die Art, wie ich den Pkey erstellt habe, nicht die richtige ist. Ich verwendete Ganzzahl nicht Null statt Seriell.postgresql - Wie kann ich den ID-Typ aller Tabellen einer vorhandenen Datenbank ändern

Wie kann ich alle P-Tasten von meinen Tabellen in den Serientyp ändern, ohne die gesamte Datenbank zu ändern?

Danke!

+0

Möglich Duplikat von [Alter Datentyp einer Spalte zu seriell] (http://stackoverflow.com/questions/16474720/alter-data-type-of-a-column-to-serial) –

Antwort

1
  • Keine Garantie (Ich grub diese und es ein wenig verändert)
  • könnten einige zusätzliche Bearbeitung
  • STELLEN SIE SICHER, müssen HABEN SIE EIN BACKUP
  • [und/oder ersten Test an einem Dummy Datenbank]
  • aus Sicherheitsgründen wird dies in einem 'tmp' Schema ausgeführt, um keinen unbeabsichtigten Schaden zu verursachen.
  • das ist ein paar Jahre alt, heute habe ich format() verwenden würde die dynamische SQL-
  • Anmerkung zu konstruieren: Das ist die altmodische Art und Weise. Vielleicht könnten Sie heutzutage einfach `alter table tab alter column typ = typ;

DROP SCHEMA tmp CASCADE; 
CREATE SCHEMA tmp ; 
SET search_path=tmp; 

     -- Create sequence for column and attacht it as a default 
     -- sch := schemaname 
     -- tab := tablename 
     -- zname := columnname 
     -- NOTE: 
     -- if 'sch' is NULL, 'public' is used 
     -- if 'tab' is NULL, *ALL* tables in the schema are affected. 
     -- 'zname' must always be supplied 
     -- ----------------------------------------------------------- 
CREATE FUNCTION inttoseq(sch text, tab text, zname text) RETURNS integer 
    LANGUAGE plpgsql 
    AS $$ 
DECLARE 
     zresult text; 
     tabname text; 
     colname text; 
     seqname text; 
     schtabname text; 
     schseqname text; 
     tabcolname text; 
     schtabcolname text; 
     zrec RECORD; 
     zcount INTEGER; 
BEGIN 
     zcount = 0; 
     FOR zrec IN 
       SELECT ns.nspname AS sname 
       , cl.relname AS tname 
       , cl.relowner AS onumm 
       , at.attname AS cname 
       FROM pg_class cl 
       JOIN pg_namespace ns ON ns.oid = cl.relnamespace 
       JOIN pg_attribute at ON at.attrelid = cl.oid 
       WHERE ns.nspname = COALESCE(sch, 'public') 
       AND (cl.relname = tab OR tab IS NULL) 
       AND (at.attname = zname) 
     LOOP 
       tabname := quote_ident(zrec.tname) 
         ; 
       schtabname := quote_ident(zrec.sname) || '.' || tabname 
         ; 
       colname := quote_ident(zrec.cname) 
         ; 
       tabcolname := tabname || '.' || colname 
         ; 
       schtabcolname := schtabname || '.' || colname 
         ; 
       seqname := trim(zrec.tname) || '_' || trim(zrec.cname) || '_seq' 
         ; 
       schseqname := quote_ident(zrec.sname) || '.' || seqname 
         ; 
       zresult := 'CREATE SEQUENCE ' || schseqname 
         || ' MINVALUE 1' 
         || ';' 
         || E'\n' 
         || 'ALTER SEQUENCE ' || schseqname 
         || ' OWNER TO ' || pg_get_userbyid(zrec.onumm) 
         || ';' 
         || E'\n' 
         || 'ALTER TABLE ' || schtabname 
         || ' ALTER COLUMN ' || colname 
         || ' SET DEFAULT nextval(' || quote_literal(schseqname) || ');' 
         || E'\n' 
         || 'ALTER SEQUENCE ' || schseqname 
         || ' OWNED BY ' || schtabcolname || ';' 
         || E'\n' 
         ; 
       -- RAISE NOTICE 'Result:=%', zresult; 
       IF (zresult IS NOT NULL) THEN 
         EXECUTE zresult; 
         zcount := zcount +1; 
       END IF; 
     END LOOP; 
       RETURN zcount; 
END; 
$$; 

ALTER FUNCTION inttoseq(sch text, tab text, zname text) OWNER TO postgres; 

     -- Set the value for a sequence to the max(value) 
     -- in the corresponding column. 
CREATE FUNCTION syncseq(sch text, tab text, zname text) RETURNS integer 
    LANGUAGE plpgsql 
    AS $$ 

DECLARE 
     zresult text; 
     tabname text; 
     colname text; 
     seqname text; 
     schtabname text; 
     schseqname text; 
     tabcolname text; 
     schtabcolname text; 
     zrec RECORD; 
     zcount INTEGER; 
BEGIN 
     zcount = 0; 
     FOR zrec IN 
       SELECT ns.nspname AS sname 
       , cl.relname AS tname 
       , cl.relowner AS onumm 
       , at.attname AS cname 
       FROM pg_class cl 
       JOIN pg_namespace ns ON ns.oid = cl.relnamespace 
       JOIN pg_attribute at ON at.attrelid = cl.oid 
       WHERE ns.nspname = COALESCE(sch, 'public') 
       AND (cl.relname = tab OR tab IS NULL) 
       AND (at.attname = zname) 
     LOOP 
       tabname := quote_ident(zrec.tname) 
         ; 
       schtabname := quote_ident(zrec.sname) || '.' || tabname 
         ; 
       colname := quote_ident(zrec.cname) 
         ; 
       tabcolname := tabname || '.' || colname 
         ; 
       schtabcolname := schtabname || '.' || colname 
         ; 
       seqname := trim(zrec.tname) || '_' || trim(zrec.cname) || '_seq' 
         ; 
       schseqname := quote_ident(zrec.sname) || '.' || seqname 
         ; 
       zresult := 'ALTER SEQUENCE ' || schseqname 
         || ' MINVALUE 1' 
         || ';' 
         || E'\n' 
         || ' SELECT setval(' 
         || quote_literal(schseqname) 
         || ', COALESCE(GREATEST(zt.' || colname || ' ,1), 1)' 
         || ', True)' 
         || ' FROM ' || schtabname || ' zt;' 
         || E'\n' 
         ; 
       -- RAISE NOTICE 'Result:=%', zresult; 
       IF (zresult IS NOT NULL) THEN 
         EXECUTE zresult; 
         zcount := zcount +1; 
       END IF; 
     END LOOP; 
       RETURN zcount; 
END; 
$$; 


ALTER FUNCTION syncseq(sch text, tab text, zname text) OWNER TO postgres; 


     -- do some testing 
CREATE TABLE app_user (
    id bigint NOT NULL 
    , username character varying NOT NULL 
); 

INSERT INTO app_user(id, username) VALUES 
(1, 'Joan') 
,(2, 'John') 
,(3, 'Bill') 
,(9, 'Hillary') 
     ; 
    -- invoke the functions to alter the PK type to SERIAL 
SELECT inttoseq('tmp', 'app_user', 'id'); 
    -- and set the serial to the max value in the column 
SELECT syncseq('tmp', 'app_user', 'id'); 

    -- show it to the world 
\d app_user 

SELECT * FROM app_user; 
SELECT nextval('app_user_id_seq'); 

\ds app_user_id_seq 

Die Namen von Beratungs die Kataloge gefunden werden konnte, für die PK suchen, aber das ist schwierig und möglicherweise gefährlich. Mit den gegebenen Funktionen müssen Sie {schemaname, tablename, spaltenname} angeben (aber Sie können Schema und Tabelle weglassen, was praktisch ist, wenn alle Ihre PKs 'id' heißen ;-)

+0

Danke für Ihre Hilfe. Ich verstehe Ihren Code, ich werde die Datenbank für die Tests freigeben. Ich bin ein Postgresql n00b, also ist es nicht trivial für mich. – marco

+0

Ich hatte einen anderen Antworter, aber der Benutzer gelöscht. Also, ich habe keine andere Option zu vergleichen – marco

+1

Die andere Antwort tut im Grunde das gleiche, aber manuell. (Erstellen Sie die Sequenz + fügen Sie sie an die PK-Spalte als DEFAULT an + setzen Sie den Maximalwert für die Sequenz auf MAX (PK)) Sie könnten die gleiche Logik aus meiner Antwort extrahieren, wenn Sie es lieber manuell machen möchten. – wildplasser

Verwandte Themen