【问题标题】:Idempotent PostgreSQL DDL scripts幂等 PostgreSQL DDL 脚本
【发布时间】:2010-10-18 10:14:08
【问题描述】:

我正在寻找一种以幂等方式编写 postgreSQL 架构更改脚本的方法。

在 MSSQL 中我可以这样做:

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 似乎不像 MSSQL 对 T-SQL 那样允许 ad-hoc pl/pgsql,所以我不能在 SQL 脚本中使用控制结构并使用 psql -f x.sql 运行它。

我知道如果对象已经存在,PostgreSQL 会抛出错误,但我不想忽略错误。

我可以使用一些模式版本控制技术,例如 dbdeploy,但我真的很喜欢通过 psql 运行一组文件而不会产生任何不必要的副作用的简单性。

这可能吗?

谢谢, 标记

【问题讨论】:

    标签: database postgresql plpgsql


    【解决方案1】:

    免责声明:我知道,这是一个非常古老的问题,并且已经有一个公认的答案。

    但我想在这里注册一个完全幂等的脚本,没有外部链接。


    演示 PostgreSQL 9.5+ 幂等内置功能的简单脚本。您可以根据需要多次运行此脚本。 开始了:
    --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;
    

    【讨论】:

      【解决方案2】:

      您可能会发现这篇博文很有帮助:http://www.depesz.com/index.php/2008/06/18/conditional-ddl/

      【讨论】:

      • 感谢 depesz。这正是我一直在寻找的东西。干杯M
      【解决方案3】:

      你应该可以使用plpgsql:

      create language plpgsql;
      create function f() ... as $$
      <plpgsql code>
      $$language plpgsql;
      select f();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-08
        • 2021-12-01
        • 2011-07-27
        • 1970-01-01
        • 2021-03-08
        • 2018-06-14
        相关资源
        最近更新 更多