Postgres是否有任何办法说ALTER TABLE foo ADD CONSTRAINT bar ...
如果约束已经存在,它将忽略该命令,从而不会引发错误?
Answers:
这可能有所帮助,尽管可能有点脏:
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的以下建议:
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
在您的开发数据库中,或者在您知道可以关闭依赖该数据库的应用程序作为维护时段的情况下,这可能很好。
但是,如果这是一个关键任务的24x7全天候生产环境,那么您真的不想像这样随意放弃约束。即使是几毫秒,也有一个很短的窗口,您不再需要执行约束,这可能会使错误的值漏掉。这可能会带来意想不到的后果,从而在将来的某些时候导致可观的业务成本。
execute 'ALTER TABLE ' || t_name || ' ADD CONSTRAINT ' || c_name || ' ' || constraint_sql;
然后调用该函数将类似于SELECT create_constraint_if_not_exists('foo', 'bar', 'CHECK (foobies < 100);');
。这可以确保您不会弄乱约束SQL中的参数,因为它们基于原始参数。
execute
句子的末尾(在之前;
),这样我就可以消除;
调用函数时自变量的结尾。
information_schema.table_constraints
。
一个可能的解决方案是在创建新约束之前简单地使用DROP IF EXISTS。
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
似乎比尝试查询information_schema或目录容易,但在大型表上可能会很慢,因为它总是重新创建约束。
编辑2015-07-13:Kev在回答中指出,当约束不存在且未强制执行时,我的解决方案会创建一个短窗口。确实如此,但是您可以通过将两个语句包装在事务中来轻松地避免这样的窗口。
您可以在匿名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
duplicate_object
为duplicate_table
(代码42P07)。Postgres 9.6
duplicate_object
。
duplicate_object
为FOREIGN KEY
。 duplicate_table
对于UNIQUE
限制。Postgres 9.6.8
您可以在pg_constraint
表上运行查询以查找约束是否存在,例如:
SELECT 1 FROM pg_constraint WHERE conname = 'constraint_name'"
IF EXISTS
对于DROP CONSTRAINT
AFAIK,有一个选项,但对没有ADD CONSTRAINT
。
constraint_name
怎样?
在包含大量数据的表上创建约束可能是一项昂贵的操作,因此,我建议不要删除约束只是为了立即之后立即再次创建约束-您只希望创建一次约束。
我选择使用与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$$;
information_schema.constraint_column_usage
改用它,这使我可以控制可以读取的名称以及表名称。
考虑到上面提到的所有答案,如果您只想检查要插入的表中是否存在约束,并且如果碰巧遇到一个约束,则以下方法会有所帮助
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
$$;
'myconstraint'
应该'bar'
在您的最后一个示例中。