首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在Oracle数据库10g中编写"IF UPDATING“触发器?

如何在Oracle数据库10g中编写"IF UPDATING“触发器?
EN

Stack Overflow用户
提问于 2017-06-30 10:11:00
回答 3查看 15.8K关注 0票数 0

我正在编写触发器,以确保只有一种类型的货币可以设置为官方货币。我的意图是编写一个“插入或更新前”触发器。插入部分运行良好,但问题是编码更新部分,因为当我尝试更新表时,我收到ORA-04091 "mutanting table“。你有什么想法吗?

表(只能设置一条记录为'Y'):

代码语言:javascript
复制
    mon_id  mon_description  mon_official
----------------------------------------------
    E            EUR              N
    D            DOL              N
    P            PES              Y

触发器:

代码语言:javascript
复制
CREATE OR REPLACE TRIGGER mon_oficial_ins_trg
BEFORE
INSERT OR UPDATE
ON monedas
FOR EACH ROW
DECLARE
    v_count  NUMBER(8);
BEGIN
    IF INSERTING THEN

        SELECT COUNT(mon_oficial)
        INTO   v_count
        FROM   monedas
        WHERE  mon_oficial = 'Y';

        IF v_count = 1 THEN
            RAISE_APPLICATION_ERROR(
                -20010, 'Only one record can be set as 'Y'');
        END IF;

    END IF;

    IF UPDATING THEN

        SELECT COUNT(:OLD.mon_oficial)
        INTO   v_count
        FROM   monedas
        WHERE  :OLD.mon_oficial = 'Y';

        IF v_count = 1 AND :NEW.mon_oficial = 'Y' THEN
                RAISE_APPLICATION_ERROR(
                    -20010, 'Only one record can be set as 'Y'');
        END IF;

    END IF;


END mon_oficial_ins_trg;
/
SHOW ERRORS;
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-06-30 13:24:50

在你代码中有两个错误

第一

代码语言:javascript
复制
SELECT COUNT(:OLD.mon_oficial)
        INTO   v_count
        FROM   monedas
        WHERE  :OLD.mon_oficial = 'Y'; 

部分,有关mutanting error的更多信息,请阅读本文

enter link description here

第二个错误,你有一个不正确的逻辑

IF v_count = 1 AND :NEW.mon_oficial = 'Y' THEN部件,因为它可以是我们的当前行

试试看

代码语言:javascript
复制
    CREATE OR REPLACE TRIGGER mon_oficial_ins_trg
BEFORE
INSERT OR UPDATE
ON monedas
FOR EACH ROW
DECLARE
    v_count  NUMBER(8);
BEGIN
    IF INSERTING THEN

        SELECT COUNT(mon_oficial)
        INTO   v_count
        FROM   monedas
        WHERE  mon_oficial = 'Y';

        IF v_count = 1 THEN
            RAISE_APPLICATION_ERROR(
                -20010, 'Only one record can be set as 'Y'');
        END IF;

    END IF;

    IF UPDATING THEN
     IF :NEW.mon_oficial = 'Y' then 
    for m in (SELECT *
        FROM   monedas
        WHERE  mon_oficial = 'Y'
        and    rownum=1) loop

            IF :NEW.mon_id <> m.mon_id  THEN
                    RAISE_APPLICATION_ERROR(
                        -20010, 'Only one record can be set as 'Y'');
            END IF;
        END IF;
        end loop;
    END IF;


END mon_oficial_ins_trg;
/
SHOW ERRORS;
票数 1
EN

Stack Overflow用户

发布于 2019-07-23 05:44:32

这可以通过AFTER INSERT或UPDATE语句触发器非常简单地完成。相同的逻辑适用于这两个操作。

SELECT COUNT(*) INTO v_count FROM MONEDAS WHERE MON_OFICIAL = 'Y';

如果v_count >1,则RAISE_APPLICATION_ERROR...

这种方法的另一个优点是:它允许语句

UPDATE MONEDAS SET MON_OFICIAL = CASE MON_ID WHEN 'A‘THEN 'Y’ELSE 'N‘END;

如果在以前的官方货币更新为N之前将MON_ID = 'A‘的行更新为Y,则行级触发器可能会引发错误。

票数 0
EN

Stack Overflow用户

发布于 2020-04-30 21:19:23

我认为这个问题最好用约束来解决,而不是触发器。我不是这个答案的作者,但我认为它在这里是相关的。在其余的答案中有一个博客文章的链接,该文章建议避免触发器,但该链接似乎不起作用。

答案在这里:https://stackoverflow.com/a/182427

以下是@tony-andrews在该答案中提供的示例:

代码语言:javascript
复制
create unique index only_one_yes on mytable
(case when col='YES' then 'YES' end);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44837574

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档