说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

父子表的更新怎么办?

编辑:说三道四文库 发布时间:2018-02-19 10:03
HTML文档下载 WORD文档下载 PDF文档下载
我现在有两张父子关系的表,
A,B,B 是A 的子表,B 的 id 与 A 的 id 为外健关联关系,且都为主健。现在,A、B 表里面都有数据,如果修改任意一个主键都会出错,怎么办?对父子表关系难道就不能修改相关联的键值了吗?请高手赐教
alter table a drop cascade constraint
我感觉这样不行!删掉级联关系之后,那如果主表中的ID 改变,而子表中没有改变,那子表不就找不着父表了?如果有级联关系,就改不了了,怎么办呢?做一个触发器,我对sql 语法不是很熟,麻烦帮忙写一段代码参考参考!谢谢!
用新的主键值拷贝一份,并且删除原来的父子记录
可以多步完成,先在主表A中插入一笔新记录,其ID为新的ID,其他字段值与要修改的ID对应的记录相同,然后UPDATE表B,将其ID更改为新的ID,然后删除表A中要修改ID的那条记录。
但是在触发器里面没法实现 。在触发器里面不允许操作本表,怎么办?
我的意思是你不能直接update已经被子表使用的ID,必须经过多步完成,所以是不能指望触发器来完成这项工作的。
我的程序不用触发器很不好办。在网页中自动生成的sql,很不好改,所以只有在数据库上打主意。那用别的,存储过程,能行吗?
那你在before update 触发器中判断若:new.id与:old.id不同(或者你的触发器就是update of id),此时通过动态SQL,'alter table temp disable constraint temp_fk'将这个外键约束先disable,然后更新子表,在after update 触发器中再通过'alter table temp enable constraint temp_fk' 使这个外键约束enable.
关键是 'alter table temp disable constraint temp_fk' 这个动态sql能不能执行?因为在trigger里面,这个表示被锁定的。我对这个不熟,见笑!
我用 select * from user_constraints where TABLE_NAME='ARCHFLIST' 
--'ARCHFLIST'  就是我的子表,得出来的  FK_ARCHFLIS_REF_11545_ARCHF 就是这个外键约束,对吧!'alter table temp disable constraint FK_ARCHFLIS_REF_11545_ARCHF',是这样吗?多谢空杯大哥关照!
是这样的,你的触发器是建立在主表上的,而disable和enable的操作是针对子表的,不过我也不知这样的动态SQL语句是否能在trigger里执行?
若还是不行,你就在程序里,在update主表的ID前后直接执行这两句SQL语句吧!
不要用自然主键作为数据表的主键,最好建立一个代理键作为数据表的主键,并使用此代理键
进行关联,这样就不会出现修改主键的问题
我在主标上建了了一个trigger如下:

CREATE OR REPLACE TRIGGER ARCHF_TRIGGER1 
BEFORE  UPDATE  
ON XBDKMIS.ARCHF 
FOR EACH ROW  
  
DECLARE  
oldID  archf.docid%type;  
newID  archf.docid%type; 
BEGIN 
newID:=:new.docid; 
oldID:=:old.docid; 
if newID!=oldID then 
execute immediate 'alter table archflist disable constraint FK_ARCHFLIS_REF_11545_ARCHF'; 
execute immediate 'update table archflist set docid=newID where docid=odlID'; 
execute immediate 'alter table archflist enable constraint FK_ARCHFLIS_REF_11545_ARCHF'; 

end if; 
END; 


执行修改操作的时候,出现如下错误:

can't commit in trigger;
error during excute trigger;
...
好像没有什么好的解决办法。上面的办法也不行。可是这个表已经建立好了,这种效果看来在触发其中是不能达到的了。不止各位还有何高见?
我去年回答过一模一样的问题,解决方案如下:

-- 建父表
SQL> create table a(id integer primary key);
Table created.

-- 建子表
SQL> create table b(id integer);
Table created.

--建立一个deferrable(可延时检验的外键,并设置初始校验方式为延时)
--这一部大概是最关键的,所谓延时校验就是在commit的时候才对约束进行合法性检查
--而建立约束的时候如果不指定延时校验那就是及时校验,dml完成以后立即进行合法性检查
SQL> alter table b add constraint fk_b_a foreign key (id) references a(id) deferrable initially deferred;
Table altered.

--插入测试数据
SQL> insert into a values (1);
1 row created.
SQL> insert into a values (2);
1 row created.
SQL> insert into b values (1);
1 row created.
SQL> insert into b values (2);
1 row created.

--建立一个触发器保证父子表中的纪录同步
SQL> create or replace trigger tri_a_1 before update on a for each row
  2  begin
  3    update b set id=:new.id
  4     where b.id=:old.id;
  5  end;
  6  /

Trigger created.

--更新父表数据
SQL> update a set id=3 where id=1;
1 row updated.

--检查结果
SQL> select * from a;
        ID
----------
         3
         2

--结果是看到子表中的纪录自动被更新了
SQL> select * from b;
        ID
----------
         3
         2

不知道我有没有误解你的意思,下面是实验
CREATE OR REPLACE TRIGGER trg_update_father
AFTER UPDATE ON father FOR EACH ROW
BEGIN
     UPDATE child SET id=:new.id WHERE
     id=:old.id;
END trg_update_father;

^_^>select * from father
  2  ;

        ID
----------
         1
         2
         3

^_^>select * from child;

        ID
----------
SERIAL
----------------------------------------------------------------------------------------------------
         1
hello

         2
world

         3
goodbye


^_^>update father set id=4 where id=1;

已更新 1 行。

^_^>select * from father;

        ID
----------
         4
         2
         3

^_^>select * from child;

        ID
----------
SERIAL
----------------------------------------------------------------------------------------------------
         4
hello

         2
world

         3
goodbye
该问题已经解决。谢谢各位。议会揭贴!
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘