我有两个表:1表示我的主要数据(表:ASSET):
ID | DESCR | TYPE1 | COUNTRY
1 | blabla1 | A1 | AT
2 | blabla2 | A2 | DE
3 | blabla3 | A2 | CH
和第二个表(TABLE:ASSET_OVERRULE):
ID | OVERRULE_COLUMN | OVERRULE_VALUE
1 | TYPE1 | A2
现在我想要一个触发器,每当有人更新表ASSET中的内容时,应该检查表ASSET_OVERRULE。如果找到具有相同ID的条目,则将新更新的值设置为ASSET_OVERRULE中的值。
这是触发器atm:
DECLARE
CURSOR assets_overrule_cur
IS
SELECT *
FROM asset_overrule
WHERE id = :NEW.id;
sTemp VARCHAR2(255):=NULL;
y NUMBER;
BEGIN
FOR assets_overrule
IN assets_overrule_cur
LOOP
sTemp := ':NEW.' || assets_overrule.OVERRULE_COLUMN || ':=''' || assets_overrule.OVERRULE_VALUE|| ''';';
execute immediate sTemp;
END LOOP;
END;
但是出现了这个错误:
无法找到知识Xpert。
我想,我需要另一种解决方案才能解决这个问题。
答案 0 :(得分:1)
您不能在动态SQL中使用:new
(或:old
)伪记录。您需要为每列使用具有单独分支的静态SQL。像
DECLARE
l_override_val asset_overrule.overrule_value%type;
BEGIN
BEGIN
SELECT overrule_value
INTO l_override_val
FROM asset_overrule
WHERE id = :new.id
AND override_column = 'TYPE1';
:new.type1 := l_override_val;
EXCEPTION
WHEN no_data_found
THEN
NULL;
END;
BEGIN
SELECT overrule_value
INTO l_override_val
FROM asset_overrule
WHERE id = :new.id
AND override_column = 'COUNTRY';
:new.country := l_override_val;
EXCEPTION
WHEN no_data_found
THEN
NULL;
END;
<<repeat for each column you want to override>>
END;
退一步说,数据模型至少显得笨重。如果要覆盖多个列值而不是让两个表的定义匹配,为什么还有单独的行?您是否真的需要更改触发器中的值而不是简单地在任何视图中执行覆盖返回数据,以便在删除覆盖时返回到系统设置值的任何内容?对于正在执行UPDATE
的应用程序来检查覆盖表并且不更新这些值或者警告用户这些值被覆盖或类似的情况,这是否有意义?
答案 1 :(得分:0)
如果我坚持使用这种数据模型,我会怎样做:
drop table test_asset;
drop table test_asset_overrule;
create table test_asset (id number,
descr varchar2(10),
type1 varchar2(5),
country varchar2(3));
create table test_asset_overrule (id number,
overrule_column varchar2(30),
overrule_value varchar2(10));
insert into test_asset
select 1, 'blabla1', 'A1', 'AT' from dual union all
select 2, 'blabla2', 'A2', 'DE' from dual union all
select 3, 'blabla3', 'A2', 'CH' from dual;
insert into test_asset_overrule
select 1, 'TYPE1', 'A2' from dual;
commit;
create or replace trigger test_asset_trg
before update on test_asset
for each row
begin
for rec in (select id,
overrule_column,
overrule_value
from test_asset_overrule
where id = :old.id
and id = :new.id)
loop
if upper(rec.overrule_column) = 'TYPE1' then
:new.type1 := rec.overrule_value;
elsif upper(rec.overrule_column) = 'COUNTRY' then
:new.country := rec.overrule_value;
end if;
end loop;
end test_asset_trg;
/
update test_asset
set type1 = 'A3';
commit;
select * from test_asset;
ID DESCR TYPE1 COUNTRY
---------- ---------- ----- -------
1 blabla1 A2 AT
2 blabla2 A3 DE
3 blabla3 A3 CH