Pau*_*rth 58 sql postgresql constraints
ALTER TABLE foo ADD CONSTRAINT bar ...如果约束已经存在,Postgres有没有办法说哪个会忽略命令,这样它就不会引发错误?
Web*_*mut 65
一种可能的解决方案是在创建新约束之前简单地使用DROP IF EXISTS.
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
Run Code Online (Sandbox Code Playgroud)
似乎比尝试查询information_schema或目录更容易,但在巨大的表上可能会很慢,因为它总是重新创建约束.
编辑2015-07-13:Kev在他的回答中指出,当约束不存在且未被强制执行时,我的解决方案会创建一个短窗口.虽然这是事实,但是通过将两个语句包装在事务中,可以非常容易地避免这样的窗口.
Kev*_*Kev 33
这可能有所帮助,虽然它可能有点肮脏的黑客:
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'
Run Code Online (Sandbox Code Playgroud)
然后打电话:
SELECT create_constraint_if_not_exists(
'foo',
'bar',
'ALTER TABLE foo ADD CONSTRAINT bar CHECK (foobies < 100);')
Run Code Online (Sandbox Code Playgroud)
更新:
根据Webmut的回答,以下建议:
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
Run Code Online (Sandbox Code Playgroud)
这在您的开发数据库中可能很好,或者您知道可以将依赖于此数据库的应用程序关闭到维护窗口.
但如果这是一个生动的关键任务关键24x7生产环境,你真的不想像这样毫无疑问地放弃限制.即使是几毫秒,也有一个短窗口,您不再强制执行约束,这可能允许错误的值滑过.这可能会产生意想不到的后果,导致在某些时候出现相当大的商业成本.
小智 20
您可以在匿名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 $$;
Run Code Online (Sandbox Code Playgroud)
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
您可以在pg_constraint表上运行查询以查找是否存在约束.
SELECT 1 FROM pg_constraint WHERE conname = 'constraint_name'"
Run Code Online (Sandbox Code Playgroud)
在包含大量数据的表上创建约束可能是一项昂贵的操作,因此,我建议不要删除约束只是为了立即之后立即再次创建约束-您只想创建一次约束。
我选择使用与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$$;
Run Code Online (Sandbox Code Playgroud)
利用它regclass可以减少冗长、提高性能并避免与模式之间的表命名冲突相关的错误:
DO $$ BEGIN
IF NOT EXISTS (SELECT FROM pg_constraint
WHERE conrelid = 'foo'::regclass AND conname = 'bar') THEN
ALTER TABLE foo ADD CONSTRAINT bar...;
END IF;
END $$;
Run Code Online (Sandbox Code Playgroud)
这也适用于其他模式中的表,例如:
DO $$ BEGIN
IF NOT EXISTS (SELECT FROM pg_constraint
WHERE conrelid = 's.foo'::regclass AND conname = 'bar') THEN
ALTER TABLE s.foo ADD CONSTRAINT bar...;
END IF;
END $$;
Run Code Online (Sandbox Code Playgroud)
使用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;
Run Code Online (Sandbox Code Playgroud)
例子:
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);');
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
40483 次 |
| 最近记录: |