【问题标题】:How to use a quoted “referencing” identifier in an Oracle trigger body如何在 Oracle 触发器主体中使用带引号的“引用”标识符
【发布时间】:2021-05-06 13:54:17
【问题描述】:

假设我有这样的触发器规范:

create table "t" (
  "i" number(10)
);

create or replace trigger "trg"
before insert on "t"
referencing new as "n"
for each row
begin
  null;
end;

如何从正文中引用"n" 标识符?这些都不起作用:

"n"."i" := 2;
:"n"."i" := 2;
":n"."i" := 2;
:n."i" := 2;

所有这些尝试都会编译,但在尝试插入表时会产生此错误:

ORA-04098: 触发器“TEST.trg”无效且重新验证失败

显然,我可以避免引用变量名,但 1) 这是关于从工具生成代码的问题,无论引用如何,它都必须正确获取此语法,以及 2) 我对正确的语法很好奇。

绑定变量

CREATE TRIGGER docs 中,有一个参考(重点是我的):

在简单触发器的 trigger_body 或复合触发器的 tps_body 中,关联名称是 绑定变量的占位符。

似乎绑定变量一般不支持引用,例如虽然这有效:

BEGIN
  EXECUTE IMMEDIATE 'BEGIN dbms_output.put_line(:x); END;' USING 'a';
END;

这个或任何类似的语法不会:

BEGIN
  EXECUTE IMMEDIATE 'BEGIN dbms_output.put_line(:"x"); END;' USING 'a';
END;

所以,这似乎是一致的,但我仍然对为什么我可以这样声明名称但似乎无法引用它的规范感到好奇。

数据库版本为 Oracle Database 18c Express Edition Release 18.0.0.0.0

【问题讨论】:

  • 这能回答你的问题吗? Change inserted value with trigger
  • 不是重复的。这是一个关于声明替代默认引用名称的语法的问题。
  • @Serg:没有
  • 注意:在我的测试中,每当代码尝试使用"作为参考时,触发器编译失败。

标签: sql oracle plsql triggers


【解决方案1】:

根据文档,这些不是普通标识符,而是“相关名称”,应为newoldparent

指定相关名称,它引用当前行的旧值、新值和父值。默认值:OLD、NEW 和 PARENT。

可以使用其他名称:

如果您的触发器与名为 OLD、NEW 或 PARENT 的表相关联,则使用此子句指定不同的相关名称以避免表名称和相关名称之间的混淆。

但您不能在对相关名称的任何引用中使用"。有趣的是,如果标识符全是大写,你可以成功引用它:

create or replace trigger "trg"
before insert on "t"
referencing new as "N"
for each row
begin
  :N."i" := 2;
  :n."i" := 2;
end;

https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/CREATE-TRIGGER-statement.html#GUID-AF9E33F1-64D1-4382-A6A4-EC33C36F237B__BABEBAAB

【讨论】:

  • 有趣的是,调用值 "N" 并将其引用为 :N 有效。对我来说,相关名称是表的名称,并且可以引用表名。将此与 SELECT clause documentation 中术语“相关名称”的用法进行比较,例如使用表别名时。我个人认为这只是一个解析器错误。 :"n" 对我来说似乎是合理的。
  • jinx :) 得到了那个 :)
  • 同意,最好是语法一致。不幸的是,我不确定在这种特殊情况下是否会有足够的需求来修复它。
  • 我更新了我的问题,提示有关绑定变量的语法。
  • 我认为将绑定变量绑定变量的占位符区分开来是很重要的。
猜你喜欢
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-30
  • 1970-01-01
  • 1970-01-01
  • 2014-10-12
相关资源
最近更新 更多