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