如何在 Oracle PL/SQL 上创建可以捕获 DUP_VAL_ON_INDEX 的前触发器或后触发器

Posted

技术标签:

【中文标题】如何在 Oracle PL/SQL 上创建可以捕获 DUP_VAL_ON_INDEX 的前触发器或后触发器【英文标题】:How to create a before or after Trigger that can catch DUP_VAL_ON_INDEX on Oracle PL/SQL 【发布时间】:2016-10-14 15:53:52 【问题描述】:

我有一张这样的桌子

KD_C KD_PLA KD_T     GABUNG   BERAKHIR    GAJI_PL     BUYOUT
---- ------ ---- ---------- ---------- ---------- ----------
C001 MA001  T006       2003       2014      50000    5200000
C002 SC001  T006       2012       2016      65000   20280000
C003 TW001  T006       2005       2018      90000   46800000
C004 TV001  T006       2008       2017      60000   24960000
C005 PC001  T001       2003       2016      80000   24960000
C006 AC001  T001       1996       2014      90000    9360000
C007 DB001  T001       2010       2016      65000   20280000
C008 EH001  T001       2011       2018      85000   44200000
C009 JC001  T002       1996       2014      60000    6240000
C010 SG001  T002       1998       2016      87000   27144000
C011 LS001  T002       2010       2018      81000   42120000
C012 PR001  T002       2004       2016      60000   18720000
C013 JH001  T003       2005       2018      72000   37440000
C014 GC001  T003       2003       2015      65000   13520000
C015 ED001  T003       2010       2018     100000   52000000
C016 GB001  T003       2010       2016      80000   24960000
C017 DG001  T004       2011       2018      73000   37960000
C018 RG001  T004       1992       2014      90000    9360000
C019 PJ001  T004       2011       2018      80000   41600000
C020 RP001  T004       2012       2017      92000   38272000
C021 GB002  T005       2006       2018     102000   53040000
C022 EA001  T005       2011       2015      70000   14560000
C023 HL001  T005       2012       2018      65000   33800000
C024 KW001  T005       2009       2017      67000   27872000
C025 MA001  T005       2017       2022      50000   26000000
C028 MA001  T001       2016       2018      15000    3120000
C029 MA001  T001       2016       2018      15000    3120000
C030 MA001  T001       2016       2018      15000    3120000

然后我尝试在复制主键时创建一个用于更新的触发器,而不是插入到表中。主键是第一列“KD_CONTRACT”。

CREATE OR REPLACE TRIGGER INSERT_TABEL_CONTRACT
BEFORE INSERT ON CONTRACT
FOR EACH ROW
DECLARE
    KODE VARCHAR2(20);
    TEMPCARIKODE NUMBER;
BEGIN
    SELECT LPAD(TO_NUMBER(NVL(SUBSTR(MAX(KD_CONTRACT),2),0))+1,3,'0') INTO KODE
    FROM CONTRACT;

    SELECT COUNT(KD_CONTRACT) INTO TEMPCARIKODE
    FROM CONTRACT
    WHERE KD_CONTRACT = :NEW.KD_CONTRACT;

    IF(TEMPCARIKODE = 0) THEN       
        :NEW.KD_CONTRACT := 'C'||KODE;
        :NEW.GABUNG := TO_NUMBER(TO_CHAR(SYSDATE,'YYYY'));
        :NEW.BERAKHIR := :NEW.GABUNG + :NEW.BERAKHIR;
        :NEW.BUYOUT := (:NEW.GAJI_PL * 52) * (:NEW.Berakhir-:NEW.Gabung) * 2;
    END IF; 
EXCEPTION
    WHEN DUP_VAL_ON_INDEX THEN
        DBMS_OUTPUT.PUT_LINE('');
        DBMS_OUTPUT.PUT_LINE('');
        DBMS_OUTPUT.PUT_LINE('ERROR at Line 1:');
        DBMS_OUTPUT.PUT_LINE('ORA-20003: Data sudah ada, data akan diupdate!');
END;
/
show err;

无论如何,代码可能表明我在主键重复时尝试不更新。但请先到最后。

它没有显示错误...所以触发器成功创建。 然后我尝试插入重复的主键。 INSERT INTO CONTRACT VALUES('C001','MA001','T001',2013,2,15000,2500000);

结果

INSERT INTO CONTRACT VALUES('C001','MA001','T001',2013,2,15000,2500000)
*
ERROR at line 1:
ORA-00001: unique constraint (TUGAS.PK_CONTRACT) violated

它确实引发了 ORA-00001,但它从未触及 DUP_VAL_ON_INDEX 并且没有显示任何内容或自定义消息。 有人有想法吗?当它甚至从未触及 DUP_VAL_ON_INDEX 时,我怎么能在 when 情况下粘贴更新查询...... 谢谢... * 无论如何,我的 oracle 是 XE 或 express 版本。

【问题讨论】:

触发代码不会抛出dup_val_on_index,因此您的异常处理程序将永远不会被调用。约束违反检查与触发器完全分开。如果你想捕获错误,任何有insert 语句的代码都需要有一个异常处理程序。 你想得到什么?乍一看,您尝试使用 inique KD_CONTRACT 插入值。如果我是对的,更合适的是使用序列。 @MichaelPiankov 啊,这就是我的问题的答案。然后我必须找到另一种方法。谢谢! @BenyaminLimanto:如果问题现在没有用,请删除它 【参考方案1】:

您的触发器中的EXCEPTION 块将永远不会执行,因为您的触发器不包含任何INSERTUPDATE 语句。 你必须考虑 INSTEAD OF 触发器。

【讨论】:

好的。我可以使用而不是同时使用 BEFORE On 吗?

以上是关于如何在 Oracle PL/SQL 上创建可以捕获 DUP_VAL_ON_INDEX 的前触发器或后触发器的主要内容,如果未能解决你的问题,请参考以下文章

如何从 oracle pl sql 中的包主体内的 select 语句中捕获特定列

Oracle PL/SQL 在循环中捕获锁定异常并继续

如何在 powershell 变量中捕获 PL SQL 函数的输出?

如何创建一个 Oracle 全局类型并在 PL/SQL 中使用它?

Oracle PL/SQL 如何创建列表列表

Oracle PL / SQL触发器,在UPDATE之前/之后仅用于识别表中已修改的列