触发执行条件满足

时间:2010-04-09 05:57:01

标签: sql oracle triggers

我创建了这个触发器,只要table-receipts1的新rctmemenrolno的值与table-memmast的memenrolno匹配,就会产生错误,但它在两个条件下都给出错误(匹配或不匹配) 。 请帮助我。

CREATE OR REPLACE TRIGGER HDD_CABLE.trg_rctenrolno
before insert ON HDD_CABLE.RECEIPTS1 for each row
declare
v_enrolno varchar2(9);
cursor c1 is select memenrolno from memmast;
begin
open c1;
fetch c1 into v_enrolno;
LOOP
    If :new.rctmemenrolno<>v_enrolno
then
raise_application_error(-20186,'PLEASE ENTER CORRECT ENROLLMENT NO');
close c1;
end if;
END LOOP;
end;

2 个答案:

答案 0 :(得分:2)

您正在验证输入的RECEIPTS1.rctmemenrolno是否与MEMAST中的memenrolno匹配,对吗?那么触发器是错误的方法。

循环完全不会缩放(MEMAST中的行越多,在RECEIPTS1中插入记录所需的时间就越长)。但即使直接查找以检查指定密钥的存在仍然会很糟糕。此方法也无法在多用户环境中安全地工作,因为Oracle使用READ COMMITTED隔离级别。换句话说,当您的交易正在进行检查时,其他会话正在删除您刚刚找到的行。这会导致数据库损坏。

唯一正确的方法是使用外键约束。

alter table receipt1
    add constraint receipts1_memast_fk foreign key (rctmemenrolno)
                  references memast (memenrolno);  

当然,这假设你有一个主键 - 或一个独特的约束 - 在memast上强制执行memenrolno的任务。我热切地希望你不要试图通过触发器强制执行唯一性。

修改

  

“我已经在memmast表上有1个主键作为MEMID”

如果MEMID和MEMENROLNO之间存在一对一的关系,这在我们拥有业务密钥和代理密钥时很常见,那么正确的解决方案是使用RECEIPTS1上的主键。也就是说,删除列RCTMEMENROL并将其替换为RCTMEMID。然后将这些列名称插入到alter table语句中。前端将负责为用户提供查找给定MEMENROLNO的MEMID的工具,例如List Of Values小部件。

更糟糕的解决方案是在MEMAST.MEMENROLNO上建立一个独特的约束。这是不可取的,因为使用自然键来强制执行外键是一个坏主意,并且当有问题的表已经具有合成主键时完全生气。

如果MEMID和MEMENROLNO之间没有一对一的关系,那么我不知道检查的目的是什么。对MEMAST的查询可以声明存在给定的MEMENROLNO 现在但没有外键,它可以在五分钟内没有说明数据库的状态。那么为什么要费心去检查呢?

答案 1 :(得分:0)

看起来你正在循环遍历memenrolno的所有可能值,并确保新值与每个可能的值匹配,当有多个memenrolno时,这将始终为false。

试试这个。

CREATE OR REPLACE TRIGGER HDD_CABLE.trg_rctenrolno
before insert ON HDD_CABLE.RECEIPTS1 for each row
begin
    If NOT EXISTS SELECT 1 FROM memast WHERE memenrolno = :new.rctmemenrolno
        then
            raise_application_error(-20186,'PLEASE ENTER CORRECT ENROLLMENT NO');
    end if;
end;