1

我有一个在更新后执行的触发器。它不像我想要的那样工作。

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

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

4 回答 4

3

在 Oracle 中,null 和空字符串实际上''等效的:

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

...所以这两个检查真的是一样的。在这两种情况下,您都在做nvl(something, null),这没有多大意义-您是在说“如果值为 null,则将其设为 null”,这是多余的并且不会进行任何真正的转换。因此,如果旧值或新值中的任何一个为 null,您仍在尝试将 null 与自身或非 null 值进行比较;正如 San 所说,您不能将 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
...
于 2015-02-10T09:59:14.647 回答
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;
于 2015-02-10T09:43:55.453 回答
0

以防万一,额外的建议。检查您使用的触发器类型?我的意思是,行触发器或语句触发器。您还可以在列上查看触发器示例:

更新列时的 Oracle SQL 触发器

于 2015-02-10T11:18:28.103 回答
0

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

如果列出现在子句中“=”的左侧,则updating系统函数返回。所以trueset

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

在更新触发器中,updating( 'col1' )并且updating( 'col2' )都将返回true. true但即使 col1 以 null 值(或 '')开始或 col2 已经是 42,它们也会返回。

因此,您似乎有两个选择:您可以像 Oracle 一样将 NULL 和 '' 视为等效且不将它们标记为更改,或者您可以标记任何尝试在该字段中进行更改,即使它原来相同的值实际上被重写到该字段。

除非有客观的业务需求强制要求其中一个,否则您(或做出这些决定的人)选择哪种方式并不重要,只要您将行为公开给需要了解的每个人。

于 2015-02-11T05:55:55.173 回答