Postgres:添加约束(如果它尚不存在)

时间:2011-07-23 16:58:22

标签: sql postgresql constraints

如果约束已经存在,Postgres有没有办法说ALTER TABLE foo ADD CONSTRAINT bar ...只会忽略命令,这样它就不会引发错误?

9 个答案:

答案 0 :(得分:59)

一种可能的解决方案是在创建新约束之前简单地使用DROP IF EXISTS。

ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;

似乎比尝试查询information_schema或目录更容易,但在巨大的表上可能会很慢,因为它总是重新创建约束。

编辑2015-07-13: Kev在his answer中指出,当约束不存在且未被强制执行时,我的解决方案会创建一个短窗口。虽然这是事实,但是通过将两个语句包装在事务中,可以很容易地避免这样的窗口。

答案 1 :(得分:28)

这可能会有所帮助,虽然这可能有点肮脏:

create or replace function create_constraint_if_not_exists (
    t_name text, c_name text, constraint_sql text
) 
returns void AS
$$
begin
    -- Look for our constraint
    if not exists (select constraint_name 
                   from information_schema.constraint_column_usage 
                   where table_name = t_name  and constraint_name = c_name) then
        execute constraint_sql;
    end if;
end;
$$ language 'plpgsql'

然后致电:

SELECT create_constraint_if_not_exists(
        'foo',
        'bar',
        'ALTER TABLE foo ADD CONSTRAINT bar CHECK (foobies < 100);')

<强>更新

根据下面的Webmut's answer建议:

ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;

这在您的开发数据库中可能很好,或者您知道可以在维护窗口中关闭依赖此数据库的应用程序。

但是,如果这是一个生动的任务关键的24x7生产环境,那么你真的不想在这样的情况下放弃限制。即使是几毫秒,也有一个短窗口,您不再强制执行约束,这可能允许错误的值滑过。这可能会产生意想不到的后果,导致在未来的某些时候出现相当大的商业成本。

答案 2 :(得分:17)

您可以在匿名DO块中使用异常处理程序来捕获重复的对象错误。

DO $$
BEGIN

  BEGIN
    ALTER TABLE foo ADD CONSTRAINT bar ... ;
  EXCEPTION
    WHEN duplicate_object THEN RAISE NOTICE 'Table constraint foo.bar already exists';
  END;

END $$;

http://www.postgresql.org/docs/9.4/static/sql-do.html http://www.postgresql.org/docs/9.4/static/plpgsql-control-structures.html http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html

答案 3 :(得分:9)

您可以在pg_constraint表上运行查询以查找是否存在约束。似乎:

SELECT 1 FROM pg_constraint WHERE conname = 'constraint_name'"

答案 4 :(得分:4)

在包含大量数据的表上创建约束可能是一项昂贵的操作,因此我建议不要仅删除约束,以便在之后立即再次创建它们 - 您只想创建一次。

我选择使用匿名代码块来解决这个问题,与Mike Stankavich非常相似,但不像Mike(捕获错误)我首先检查是否存在约束:

DO $$
BEGIN
    IF NOT EXISTS ( SELECT  constraint_schema
                ,       constraint_name 
                FROM    information_schema.check_constraints 
                WHERE   constraint_schema = 'myschema'
                  AND   constraint_name = 'myconstraintname'
              )
    THEN
        ALTER TABLE myschema.mytable ADD CONSTRAINT myconstraintname CHECK (column <= 100);
    END IF;
END$$; 

答案 5 :(得分:1)

在 psql 中,您可以使用元命令 \gexec 来运行生成的查询。

SELECT 'ALTER TABLE xx ADD CONSTRAINT abc' WHERE not EXISTS (SELECT True FROM pg_constraint WHERE conname = 'abc') \gexec

答案 6 :(得分:1)

使用information_schema.constraint_column_usage 来检查约束不适用于外键。我使用 pg_constraint 来检查主键外键唯一约束:

CREATE OR REPLACE FUNCTION add_constraint(t_name text, c_name text, constraint_sql text)
RETURNS void
AS $$
BEGIN
    IF NOT EXISTS(
            SELECT c.conname
            FROM pg_constraint AS c
            INNER JOIN pg_class AS t ON c.conrelid = t."oid"
            WHERE t.relname = t_name AND c.conname = c_name
    ) THEN

        EXECUTE 'ALTER TABLE ' || t_name || ' ADD CONSTRAINT ' || c_name || ' ' || constraint_sql;

    END IF;
END;
$$
LANGUAGE plpgsql;

示例:

SELECT add_constraint('client_grant_system_scopes', 'client_grant_system_scopes_pk', 'PRIMARY KEY (client_grants_id, tenant, "scope");');

SELECT add_constraint('client_grant_system_scopes', 'client_grant_system_scopes_fk', 'FOREIGN KEY (tenant,"scope") REFERENCES system_scope(tenant,"scope") ON DELETE CASCADE;');

SELECT add_constraint('jwt_assertion_issuers', 'jwt_assertion_issuers_issuer_key', 'UNIQUE (issuer);');

答案 7 :(得分:-1)

考虑到上面提到的所有答案,如果您只想检查要插入的表中是否存在约束,并在碰巧出现一个约束时发出通知,则以下方法会有所帮助

DO 
$$ BEGIN
IF NOT EXISTS (select constraint_name 
               from information_schema.table_constraints 
               where table_schema='schame_name' and upper(table_name) = 
upper('table_name')  and upper(constraint_name) = upper('constraint_name'))

THEN

   ALTER TABLE TABLE_NAME ADD CONSTRAINT CONTRAINT_NAME..... ;

ELSE raise NOTICE 'Constraint CONTRAINT_NAME already exists in Table TABLE_NAME';   

END IF;
END
$$;

答案 8 :(得分:-3)

不知道为什么这么多行代码?

- SELECT&#34; Column1&#34;,&#34; Column2&#34;,&#34; Column3&#34; ,计数(明星)来自dbo。&#34; MyTable&#34; GROUP BY&#34; Column1&#34; ,&#34; Column2&#34; ,&#34; Column3&#34;有计数(*)&gt; 1;

改变表dbo。&#34; MyTable&#34; drop constraint如果存在&#34; MyConstraint_Name&#34; ;

ALTER TABLE dbo。&#34; MyTable&#34;添加约束&#34; MyConstraint_Name&#34; UNIQUE(&#34; Column1&#34;,&#34; Column3&#34;,&#34; Column2&#34;);