Frage

Ich bin auf der Suche nach einem Weg, um Skript postgreSQL Schemaänderungen in einer Idempotent Weise.

In MSSQL ich so etwas tun könnte:

if(not exists(select * from information_schema.columns where table_name = 'x' and column_name = 'y'))
begin
    alter table x add y int
end
go

PostgreSQL scheint nicht ad-hoc pl / pgsql in der gleichen Art und Weise zu ermöglichen, MSSQL hat mit T-SQL, so kann ich nicht Kontrollstrukturen in einem SQL-Skript verwenden und es mit psql -f x.sql laufen.

ich weiß, PostgreSQL wirft einen Fehler, wenn das Objekt bereits vorhanden ist, aber ich will keine Fehler zu ignorieren, haben.

konnte ich einige Schema Versionierung Technik wie dbdeploy benutzen, aber ich mag die Einfachheit der eine Reihe von Dateien durch psql laufen, ohne unerwünschte Nebenwirkungen zu verursachen.

Ist das möglich?

Danke, Mark

War es hilfreich?

Lösung

Andere Tipps

Haftungsausschluss:. Ich weiß, das ist eine sehr alte Frage und hat bereits eine akzeptierte Antwort

Aber ich möchte hier ein völlig Idempotent Skript registrieren, ohne externe Links.


Ein einfaches Skript-Funktionen PostgreSQL 9.5+ Idempotent integrierten demonstrieren. Sie können dieses Skript so oft laufen, wie Sie es wünschen. Los geht's:

--Table
CREATE TABLE IF NOT EXISTS person (
  id integer NOT NULL,
  person_name character varying(40) NOT NULL,
  updated_date date,
  CONSTRAINT person_pkey PRIMARY KEY (id)
);

--Index
CREATE INDEX IF NOT EXISTS idx_person_name ON person (person_name);

--Sequence
CREATE SEQUENCE IF NOT EXISTS seq_person_inc;

--Function
CREATE OR REPLACE FUNCTION simple_sum(a_integer int, b_integer int) RETURNS INT
    AS $$ SELECT a_integer+b_integer $$
LANGUAGE SQL;

--View
CREATE OR REPLACE VIEW vw_select_1 AS
    SELECT 1;

--Role
DO $$
BEGIN
    CREATE ROLE rick_deckard;    
EXCEPTION   
    WHEN duplicate_object THEN
        RAISE NOTICE 'Role already exists. Ignoring...';    
END$$;

--Simple insert
INSERT INTO person (id, person_name) VALUES (1, 'HAL-9000'); 

--Upsert (insert + update)
INSERT INTO person (id, person_name) VALUES (1, 'Betrayer') ON CONFLICT ON CONSTRAINT person_pkey DO UPDATE SET person_name = EXCLUDED.person_name;

--Upsert (ignoring duplicate error)
INSERT INTO person (id, person_name) VALUES (1, 'HAL-9000') ON CONFLICT ON CONSTRAINT person_pkey DO NOTHING;

--Upsert (ignoring any error)
INSERT INTO person (id, person_name) VALUES (1, 'HAL-9000') ON CONFLICT DO NOTHING;

--Field
DO $$
BEGIN
    ALTER TABLE person ADD COLUMN id_another_person INTEGER;
EXCEPTION   
    WHEN duplicate_column THEN
        RAISE NOTICE 'Field already exists. Ignoring...';
END$$;

--Constraint
DO $$
BEGIN
    ALTER TABLE person ADD CONSTRAINT person_id_another_person_fkey FOREIGN KEY (id_another_person) REFERENCES person (id);
EXCEPTION   
    WHEN duplicate_object THEN
        RAISE NOTICE 'Constraint already exists. Ignoring...';
END$$;

--Trigger
CREATE OR REPLACE FUNCTION person_trigger_function() RETURNS trigger AS $BODY$
BEGIN
   --Something complex here =)
   RETURN NEW; 
END;
$BODY$
LANGUAGE plpgsql;

DO $$
BEGIN
    CREATE TRIGGER person_trigger BEFORE INSERT OR UPDATE ON person FOR EACH ROW EXECUTE PROCEDURE person_trigger_function();
EXCEPTION   
    WHEN duplicate_object THEN
        RAISE NOTICE 'Trigger already exists. Ignoring...';
END$$;

--Drop
DROP TRIGGER IF EXISTS person_trigger ON person;
DROP INDEX IF EXISTS idx_person_name;
ALTER TABLE person DROP COLUMN IF EXISTS person_name;
ALTER TABLE person DROP CONSTRAINT IF EXISTS person_id_another_person_fkey;
DROP ROLE IF EXISTS rick_deckard;
DROP VIEW IF EXISTS vw_select_1;
DROP FUNCTION IF EXISTS simple_sum(integer, integer);
DROP FUNCTION IF EXISTS person_trigger_function();
DROP TABLE IF EXISTS person;
DROP SEQUENCE IF EXISTS seq_person_inc;

Es soll möglich sein, plpgsql :

create language plpgsql;
create function f() ... as $$
<plpgsql code>
$$language plpgsql;
select f();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top