我有一个 SQL 脚本,需要删除多个约束并在最后恢复它们,但约束名称是自动生成的,并且每次运行脚本时都会不同。
我知道如何从表名称中获取约束名称,但似乎不可能在 drop 语句中使用此信息。
select conname from pg_constraint where
conrelid = (select oid from pg_class where relname='table name')
and confrelid = (select oid from pg_class where relname='reference table');
alter table something drop constraint (some subquery)
是一个语法错误。
理想情况下,我想获取约束名称并将其存储在变量中,但 Postgres 似乎不支持这一点,并且我无法使其与 psql 一起使用
\set
。
这可能吗?
要动态删除和重新创建外键约束,您可以将其全部包装在
FUNCTION
、PROCEDURE
(Postgres 11+)或 DO
命令中:
DO
$do$
DECLARE
/* There could be multiple FK constraints one table to another (even if uncomon).
* This kind of assignment raises an exception if more than one rows are found:
* "ERROR: more than one row returned by a subquery used as an expression"
* (As opposed to SELECT INTO ...)
* If that's not what you want, resolve it.
*/
_con text := (
SELECT quote_ident(conname)
FROM pg_constraint
WHERE conrelid = 'myschema.mytable'::regclass -- source table
AND confrelid = 'myschema.myreftable'::regclass -- FK target table
);
BEGIN
IF _con IS NULL THEN
RAISE EXCEPTION 'FK constraint not found!'; -- flesh out msg ...
END IF;
EXECUTE
'ALTER TABLE myschema.mytable DROP CONSTRAINT ' || _con;
-- do stuff here
EXECUTE
'ALTER TABLE myschema.mytable
ADD CONSTRAINT ' || _con || ' FOREIGN KEY (col)
REFERENCES myschema.myreftable (col)';
END
$do$;
执行角色必须拥有要使用的表
ALTER TABLE
(或者是超级用户)。SECURITY DEFINER
函数,并且:
ALTER FUNCTION foo() OWNER TO table_owner;
table_owner
是表的所有者(或超级用户)。但请阅读手册中有关安全性的内容。
您也可以使用存储过程。
CREATE OR REPLACE PROCEDURE public.p_costraint()
LANGUAGE plpgsql
AS $procedure$
DECLARE _constrint text;
begin
-- for dynamic change the constraint.
_constrint := (
SELECT quote_ident(conname)
FROM pg_constraint
WHERE conrelid = 'test.contacts'::regclass
AND confrelid = 'test.customers'::regclass
LIMIT 1 -- there could be multiple fk constraints. Deal with it ...
);
_constrint := _constrint || 'test';
EXECUTE '
ALTER TABLE test.contacts
ADD CONSTRAINT ' || _constrint || ' FOREIGN KEY (customer_id)
REFERENCES test.customers (customer_id)';
RAISE NOTICE 'hello, world!';
end
$procedure$;
在这里。约束名称用作文本变量。
你可以直接称呼它:
call public.p_costraint();
NOTICE: hello, world!
CALL