我有一个在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;
有什么想法吗?
亲切的问候,
答案 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? 我的意思是,行触发器或语句触发器。 您还可以在列上看到触发器的示例:
答案 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;为了等同而不将它们标记为更改,或者您可以标记任何尝试在字段中进行更改,即使事实证明实际上正在重写到字段的相同值
除非有一个客观的业务要求强制要求另一个,否则只要您向需要知道的每个人宣传行为,您(或做出这些决定的人)选择的方式并不重要。