Oracle 中的触发器未正确执行 PL/SQL
Trigger not executing correctly in Oracle PL/SQL
我有一个在更新后执行的触发器。它没有像我想要的那样工作。
我如何检查可为空类型的字段上的值是否已更改?我有以下可为空类型的字段:
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;
有什么想法吗?
亲切的问候,
您不能将 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;
在Oracle中,null和空字符串''
是effectively equivalent:
Oracle Database currently treats a character value with a length of zero as null. However, this may not continue to be true in future releases, and Oracle recommends that you do not treat empty strings the same as nulls.
...所以两次检查真的是一样的。在这两种情况下,您都在做 nvl(something, null)
,这没有多大意义 - 您在说 "if the value is null then make it null",这是多余的,不会进行任何真正的转换。因此,如果旧值或新值中的任何一个为 null,您仍在尝试将 null 与其自身或非空值进行比较;正如 San 所说,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
...
以防万一,其他建议。检查 type 您使用的触发器?
我的意思是,行触发器或语句触发器。
您还可以在列上看到触发器的示例:
Oracle SQL trigger on update of column
虽然 Oracle 确实(暂时)认为空字符串和 NULL 是等价的,但 Oracle 的好心人为我们提供了一种捕捉变化的简单方法——但它可能不是你想要什么。
updating
系统函数 returns true
如果列出现在 set
子句中“=”的左侧。所以
update table1
set col1 = null,
col2 = 42
where ...;
在更新触发器中,updating( 'col1' )
和 updating( 'col2' )
都将 return true
。但是他们会 return true
即使 col1 以空值(或'')开始或 col2 已经是 42.
所以看起来您有两个选择:您可以像 Oracle 一样,将 NULL 和 '' 视为等同的并且不将它们标记为更改,或者您可以标记任何 尝试 在字段中进行更改,即使结果是相同的值实际上被重写到字段中。
除非有一项 objective 业务要求强制其中一个,否则您(或做出这些决定的任何人)选择哪种方式真的无关紧要,只要您将这种行为宣传给每个人需要知道。
我有一个在更新后执行的触发器。它没有像我想要的那样工作。
我如何检查可为空类型的字段上的值是否已更改?我有以下可为空类型的字段:
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;
有什么想法吗?
亲切的问候,
您不能将 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;
在Oracle中,null和空字符串''
是effectively equivalent:
Oracle Database currently treats a character value with a length of zero as null. However, this may not continue to be true in future releases, and Oracle recommends that you do not treat empty strings the same as nulls.
...所以两次检查真的是一样的。在这两种情况下,您都在做 nvl(something, null)
,这没有多大意义 - 您在说 "if the value is null then make it null",这是多余的,不会进行任何真正的转换。因此,如果旧值或新值中的任何一个为 null,您仍在尝试将 null 与其自身或非空值进行比较;正如 San 所说,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
...
以防万一,其他建议。检查 type 您使用的触发器? 我的意思是,行触发器或语句触发器。 您还可以在列上看到触发器的示例:
Oracle SQL trigger on update of column
虽然 Oracle 确实(暂时)认为空字符串和 NULL 是等价的,但 Oracle 的好心人为我们提供了一种捕捉变化的简单方法——但它可能不是你想要什么。
updating
系统函数 returns true
如果列出现在 set
子句中“=”的左侧。所以
update table1
set col1 = null,
col2 = 42
where ...;
在更新触发器中,updating( 'col1' )
和 updating( 'col2' )
都将 return true
。但是他们会 return true
即使 col1 以空值(或'')开始或 col2 已经是 42.
所以看起来您有两个选择:您可以像 Oracle 一样,将 NULL 和 '' 视为等同的并且不将它们标记为更改,或者您可以标记任何 尝试 在字段中进行更改,即使结果是相同的值实际上被重写到字段中。
除非有一项 objective 业务要求强制其中一个,否则您(或做出这些决定的任何人)选择哪种方式真的无关紧要,只要您将这种行为宣传给每个人需要知道。