【问题标题】:Trying to modify a constraint in PostgreSQL尝试修改 PostgreSQL 中的约束
【发布时间】:2011-11-30 17:35:24
【问题描述】:

我检查了 Oracle 提供的文档并找到了一种在不删除表的情况下修改约束的方法。问题是,它在修改时出错,因为它无法识别关键字。

为 PostgreSQL 使用 EMS SQL 管理器。

Alter table public.public_insurer_credit MODIFY CONSTRAINT public_insurer_credit_fk1
    deferrable, initially deferred;

我可以通过删除约束来解决它:

ALTER TABLE "public"."public_insurer_credit"
  DROP CONSTRAINT "public_insurer_credit_fk1" RESTRICT;

ALTER TABLE "public"."public_insurer_credit"
  ADD CONSTRAINT "public_insurer_credit_fk1" FOREIGN KEY ("branch_id", "order_id", "public_insurer_id")
    REFERENCES "public"."order_public_insurer"("branch_id", "order_id", "public_insurer_id")
    ON UPDATE CASCADE
    ON DELETE NO ACTION
    DEFERRABLE 
    INITIALLY DEFERRED;

【问题讨论】:

  • 您在使用 PostgreSQL 时为什么要检查 Oracle 文档(并用 'plsql' 标记这个问题)?确切的错误是什么(无法​​识别哪个关键字)?
  • 错误:“修改”第 1 行或附近的语法错误:更改表 public.public_insurer_credit 修改约束 p...^(0.359 秒)
  • 检查 Oracle 文档中的 Postgres,然后指责 Postgres。史诗。
  • 我是个菜鸟,正在检查提供给我的文档。我从来没有想过 DBA 会给我错误的文档。评论是值得的。
  • @MISMajorDeveloperAnyways 每个人都曾经是菜鸟,唯一的遗憾就是忘记了这一点。至少您提到它们是 Oracle 文档,所以很容易弄清楚。评论不值得。

标签: sql postgresql alter


【解决方案1】:

Postgres 中没有用于约束的ALTER 命令。完成此操作的最简单方法是删除约束并使用所需参数重新添加它。当然,约束的任何更改都将针对当前表数据运行。

BEGIN;
ALTER TABLE t1 DROP CONSTRAINT ...
ALTER TABLE t1 ADD CONSTRAINT ...
COMMIT;

【讨论】:

  • 注意:如果我理解正确,DDL 语句会在表上使用 AccessExclusive 锁,因此如果这些命令需要很长时间,您的站点将停止运行,直到命令完成。 documentation page 有更多详细信息,包括如何显式指定索引而不是自动生成索引。
  • 单笔交易好。单个命令甚至更好。示例:stackoverflow.com/a/31419767/939860
【解决方案2】:

根据正确的手册(由 PostgreSQL 提供,不是由 Oracle 提供),ALTER TABLE 语句中没有可用的修改约束:

这里是正确手册的链接:

http://www.postgresql.org/docs/current/static/sql-altertable.html

【讨论】:

  • 感谢您提供指向正确文档的链接。我们的 DBA 向我提供了 Oracle PL/SQL 文档。数字。
  • Oracle 和 Oracle 的 PL/SQL 是完全不同的东西。他们这样做的唯一可能原因是您使用的是 EnterpriseDB 的 Advanced Server,它支持 Oracle 的 PL/SQL(和其他 Oracle 兼容性特性)。但是他们应该给你 EnterpriseDB 手册,而不是 Oracle 手册
  • 对downvote的最佳猜测,答案只是链接到外部站点,而不向未来的读者解释如何正确更改约束。
【解决方案3】:

从 9.4 版开始,PostgreSQL 支持 ALTER TABLE ... ALTER CONSTRAINT 作为外键。

此功能将"Allow constraint attributes to be altered, so the default setting of NOT DEFERRABLE can be altered to DEFERRABLE and back." 看着您的问题,我认为这(某种)是您一直在寻找的。​​p>

更多详细信息和示例可以在这里找到:
http://www.depesz.com/2013/06/30/waiting-for-9-4-alter-table-alter-constraint-for-fks/

【讨论】:

  • 请注意,9.4 文档说 Currently only foreign key constraints may be altered.!
【解决方案4】:

ALTER CONSTRAINT 需要知道外键名称,这并不总是很方便。

这里是函数,你只需要知道表名和列名。 用法:

select replace_foreign_key('user_rates_posts', 'post_id', 'ON DELETE CASCADE');

功能:

CREATE OR REPLACE FUNCTION 
    replace_foreign_key(f_table VARCHAR, f_column VARCHAR, new_options VARCHAR) 
RETURNS VARCHAR
AS $$
DECLARE constraint_name varchar;
DECLARE reftable varchar;
DECLARE refcolumn varchar;
BEGIN

SELECT tc.constraint_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name 
FROM 
    information_schema.table_constraints AS tc 
    JOIN information_schema.key_column_usage AS kcu
      ON tc.constraint_name = kcu.constraint_name
    JOIN information_schema.constraint_column_usage AS ccu
      ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' 
   AND tc.table_name= f_table AND kcu.column_name= f_column
INTO constraint_name, reftable, refcolumn;

EXECUTE 'alter table ' || f_table || ' drop constraint ' || constraint_name || 
', ADD CONSTRAINT ' || constraint_name || ' FOREIGN KEY (' || f_column || ') ' ||
' REFERENCES ' || reftable || '(' || refcolumn || ') ' || new_options || ';';

RETURN 'Constraint replaced: ' || constraint_name || ' (' || f_table || '.' || f_column ||
 ' -> ' || reftable || '.' || refcolumn || '); New options: ' || new_options;

END;
$$ LANGUAGE plpgsql;

注意:此函数不会复制初始外键的属性。 它只需要外部表名/列名,删除当前键并替换为新键。

【讨论】:

  • 非常有趣的解决方案
猜你喜欢
  • 1970-01-01
  • 2015-01-22
  • 1970-01-01
  • 2016-06-11
  • 1970-01-01
  • 2010-12-16
  • 1970-01-01
  • 2014-05-23
  • 1970-01-01
相关资源
最近更新 更多