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

触发器在Oracle PL/SQL中未正确执行,oracle,plsql,triggers,null,nvl,Oracle,Plsql,Triggers,Null,Nvl,我有一个在更新后执行的触发器。它没有按我希望的那样工作 如何检查可为null类型的字段上的值是否已更改?我有以下可为空类型的字段: FRM_DATE DATE FRM_TIME DATE THE_DATE DATE THE_TIME NUMBER(4,2) THE_BOOL NUMBER(2) 我只想在上述字段的值实际发生变化时执行一组逻辑。如果值相同,那么我不希望代码执行。因此,在UI中,假设其中一个字段有一个值,用户将其删除(现在为空)并点击submit按钮,我希望执行

我有一个在更新后执行的触发器。它没有按我希望的那样工作

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

FRM_DATE   DATE
FRM_TIME   DATE
THE_DATE   DATE
THE_TIME   NUMBER(4,2)
THE_BOOL   NUMBER(2)
我只想在上述字段的值实际发生变化时执行一组逻辑。如果值相同,那么我不希望代码执行。因此,在UI中,假设其中一个字段有一个值,用户将其删除(现在为空)并点击submit按钮,我希望执行我的逻辑,因为已经进行了更改

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

IF (nvl(:old.FRM_DATE, '') <> nvl(:new.FRM_DATE,'')) THEN
   --My logic
END IF;
如果(nvl(:old.FRM_DATE“”)nvl(:new.FRM_DATE“”)那么
--我的逻辑
如果结束;
我也试过了

IF (nvl(:old.FRM_DATE, NULL) <> nvl(:new.FRM_DATE,NULL)) THEN
  --My logic
END IF;
如果(nvl(:old.FRM_DATE,NULL)nvl(:new.FRM_DATE,NULL))那么
--我的逻辑
如果结束;
有什么想法吗


请注意,

您不能将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;
如果(nvl(:old.FRM_DATE,to_DATE('01-01-1900','dd-mm-yyyy'))nvl(:new.FRM_DATE,to_DATE('01-01-1900','dd-mm-yyyy')),则
--我的逻辑
如果结束;

在Oracle中,null和空字符串
'
是:

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

。。。所以这两张支票实际上是一样的。在这两种情况下,您都在执行
nvl(something,null)
,这没有多大意义-您说的是“如果值为null,则将其设置为null”,这是多余的,并且不会执行任何真正的转换。因此,如果旧值或新值为null,您仍然试图将null与自身或非null值进行比较;正如桑所说

您可以使用神奇的值,正如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
...

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


虽然Oracle(目前)确实认为空字符串和NULL是等价的,但Oracle的好人为我们提供了一种简单的方法来捕捉变化——但这可能不是您想要的

如果列出现在
set
子句中“=”的左侧,则
更新
系统函数将返回
true
。所以

update  table1
    set col1 = null,
        col2 = 42
where  ...;
在更新触发器中,
更新('col1')
更新('col2')
都将返回
true
。但即使col1以空值(或“”)开始,或者col2已经是42,它们也将返回
true

这样看来,你有两种选择:要么你可以像Oracle一样考虑NULL和“等价”,不要把它们标记为一个改变,或者你可以标记任何试图改变字段的尝试,即使原来相同的值实际上被重写到字段。


除非有客观的业务需求要求一种方式优于另一种方式,否则你(或做出这些决定的人)选择哪种方式并不重要,只要你向需要知道的每个人公布行为。

我认为OP是在试图检测到对null的更改,而不是区分null和空字符串;部分原因是示例列是日期。感谢您的所有输入。