【发布时间】:2011-02-15 17:23:50
【问题描述】:
有没有办法改变另一个表作为外键引用的主键的值?
【问题讨论】:
标签: database oracle foreign-keys primary-key
有没有办法改变另一个表作为外键引用的主键的值?
【问题讨论】:
标签: database oracle foreign-keys primary-key
另一种更简单的方法是插入新行并删除旧行。 (在删除之前更新其他表中的任何引用行)
【讨论】:
如果您要这样做,则没有内置的 UPDATE CASCADE。您需要执行诸如禁用任何 FK 约束之类的操作;运行更新语句;重新启用约束。
请注意,更新主键(通常总是)是个坏主意。
【讨论】:
您需要在更改主键值之前禁用外键约束,然后再重新启用它们。
如果您确实想实现“更新级联”功能,请参阅Tom Kyte's Update Cascade package
【讨论】:
如果您只想交换密钥(这也是更改的子集,因此它可能仍然是您问题的答案),即使没有禁用约束也是可能的。我在这里写了一个例子:https://stackoverflow.com/a/26584576/1900739
update MY_TABLE t1
set t1.MY_KEY = (case t1.MY_KEY = 100 then 101 else 100 end)
where t1.MYKEY in (100, 101)
【讨论】:
是的,有一种方法可以在 Oracle 中进行级联更新,即使在事务中也是如此(这不适用于启用/禁用约束的选项)。但是,您必须自己实现它。可以通过更新前/更新后触发器来完成。
这是可能的,因为触发器是在检查任何约束之前执行的。 (嗯,至少在 Oracle 11.2 中是这样。还没有对照 12.1 进行检查,但老实说,我相信它没有改变。)
无论如何,如前所述,更新主键通常是个坏主意。
【讨论】:
原则是禁用约束,根据键运行 udates,然后重新启用约束。这是一个运行禁用脚本的脚本: (假设所有约束都在开始时启用)
生成脚本
SELECT 'alter table ' || uc.table_name|| ' disable constraint '|| uc.constraint_name|| ' ;'
FROM user_constraints uc inner join user_cons_columns ucc on uc.constraint_name = ucc.constraint_name where column_name = 'MYCOLUMN_USED_AS_FOREIGN_KEY' and constraint_type='R'
复制/粘贴生成的脚本并运行它
alter table MYTABLE1 disable constraint FK_MYTABLE1 ;
alter table MYTABLE2 disable constraint MYTABLE2 ;
alter table MYTABLE3 disable constraint FK3_MYTABLE3 ;
...
然后更新您的 PK 值:
update MYTABLE1 set MYFIELD= 'foo' where MYFIELD='bar';
update MYTABLE2 set MYFIELD= 'foo' where MYFIELD='bar';
update MYTABLE3 set MYFIELD= 'foo' where MYFIELD='bar';
commit;
生成启用约束脚本:
SELECT 'alter table ' || uc.table_name|| ' enable constraint '|| uc.constraint_name|| ' ;'
FROM user_constraints uc inner join user_cons_columns ucc on uc.constraint_name = ucc.constraint_name where column_name = 'MYCOLUMN_USED_AS_FOREIGN_KEY' and constraint_type='R'
【讨论】:
您可以做到这一点的另一种方法是更改外键约束,以便将约束的验证推迟到您提交之前 - 即 Oracle 不是逐个语句验证约束,而是按事务执行-交易。
请注意,您不能通过“alter table”语句执行此操作,但您可以删除并重新创建可延迟的外键约束,即:
alter table <table name> drop constraint <FK constraint name>;
alter table <table name> add constraint <FK constraint name> foreign key .... initially deferrable;
完成此操作后,只需按照您喜欢的任何顺序更新表格,然后提交 - 此时,任一:
请注意,此功能非常安全,因为 Oracle 不允许脏读,因此他们只会在您提交后才能看到更新的效果。因此,从其他所有会话的角度来看,参照完整性似乎得到了保留。
此外,这是一次性更改,因此您无需在每次要更新主键时都执行 DDL。
【讨论】: