触发器在Oracle PL / SQL中未正确执行

时间:2015-02-10 09:30:31

标签: oracle plsql triggers null nvl

我有一个在AFTER UPDATE上执行的触发器。它并不像我想要的那样工作。

如何在可空类型的字段上检查值是否已更改?我有以下可以为空类型的字段:

FRM_DATE   DATE
FRM_TIME   DATE
THE_DATE   DATE
THE_TIME   NUMBER(4,2)
THE_BOOL   NUMBER(2)

我想仅在上述字段的值实际发生变化时才执行一组逻辑。如果值相同,那么我不想编码执行。因此,从UI中,假设其中一个字段有一个值并且用户将其删除(现在变为NULL)并点击提交按钮,我希望我的逻辑能够执行,因为已经进行了更改。

我尝试了以下操作,但它没有执行我想要的逻辑:

IF (nvl(:old.FRM_DATE, '') <> nvl(:new.FRM_DATE,'')) THEN
   --My logic
END IF;

我也试过

IF (nvl(:old.FRM_DATE, NULL) <> nvl(:new.FRM_DATE,NULL)) THEN
  --My logic
END IF;

有什么想法吗?

亲切的问候,

4 个答案:

答案 0 :(得分:3)

在Oracle中,null和空字符串''effectively equivalent

  

Oracle数据库当前将长度为零的字符值视为null。但是,在将来的版本中可能不会继续这样,Oracle建议您不要将空字符串视为空值。

...所以这两个检查真的是一样的。在这两种情况下,你正在做nvl(something, null),这没有多大意义 - 你说的是“如果值为null则将其设为null”,这是多余的,并且不会进行任何真正的转换。因此,如果旧值或新值为null,您仍然试图将null与其自身或非空值进行比较;正如桑所说,you can't compare null with anything using equality conditions

你可以再次使用魔术值,如San所示,但你必须确保它永远不会真正出现在数据中。如果您明确检查is null

,它可能更安全,并使意图更清晰
IF (:old.FRM_DATE IS NULL AND :new.FRM_DATE IS NOT NULL)
  OR (:old.FRM_DATE IS NOT NULL AND :new.FRM_DATE IS NULL)
  OR :old.FRM_DATE != :new.FRM_DATE
THEN
...

答案 1 :(得分:0)

您无法将null与null或null与任何其他值进行比较,请将逻辑更改为:

IF (nvl(:old.FRM_DATE, to_date('01-01-1900', 'dd-mm-yyyy')) <> nvl(:new.FRM_DATE,to_date('01-01-1900', 'dd-mm-yyyy'))) THEN
   --My logic
END IF;

答案 2 :(得分:0)

以防万一,还有其他建议。检查您使用的触发器type? 我的意思是,行触发器或语句触发器。 您还可以在列上看到触发器的示例:

Oracle SQL trigger on update of column

答案 3 :(得分:0)

虽然Oracle认为(暂时)是一个空字符串而NULL是等价的,但Oracle的优秀人员为我们提供了一种简单的方法来捕捉变化 - 但它可能不是你的意思想。

如果列出现在&#34; =&#34;左侧,updating系统函数将返回true。在set子句中。所以

update  table1
    set col1 = null,
        col2 = 42
where  ...;

在更新触发器中,updating( 'col1' )updating( 'col2' )都会返回true。但即使col1以空值(或&#39;&#39;)开头,或者col2已经是42,它们也会返回true

所以看起来你有两个选择:你可以像Oracle一样考虑NULL和&#39;&#39;为了等同而不将它们标记为更改,或者您可以标记任何尝试在字段中进行更改,即使事实证明实际上正在重写到字段的相同值

除非有一个客观的业务要求强制要求另一个,否则只要您向需要知道的每个人宣传行为,您(或做出这些决定的人)选择的方式并不重要。