PL/SQL 评估顺序

Posted

技术标签:

【中文标题】PL/SQL 评估顺序【英文标题】:PL/SQL Evaluation Order 【发布时间】:2008-10-09 16:36:11 【问题描述】:

你好。考虑以下几点:

SQL> DECLARE
  2     b1   BOOLEAN;
  3     b2   BOOLEAN;
  4     FUNCTION checkit RETURN BOOLEAN IS
  5     BEGIN
  6        dbms_output.put_line('inside checkit');
  7        RETURN TRUE;
  8     END checkit;
  9  
 10     PROCEDURE outp(n VARCHAR2, p BOOLEAN) IS
 11     BEGIN
 12        IF p THEN
 13           dbms_output.put_line(n||' is true');
 14        ELSE
 15           dbms_output.put_line(n||' is false');
 16        END IF;
 17     END;
 18  BEGIN
 19     b1 := TRUE OR checkit;
 20     outp('b1',b1);
 21     b2 := checkit OR TRUE;
 22     outp('b2',b2);
 23  END;
 24  /

b1 is true
inside checkit
b2 is true

PL/SQL procedure successfully completed

SQL> 

请注意,OR 语句的结果取决于顺序。如果我先调用函数,那么无论其他项的值如何,都会执行该函数。似乎从左到右评估 OR 语句,直到获得 TRUE,此时处理停止并且结果为 TRUE。

我的问题是,这是我可以依赖的东西吗?或者这种行为会在未来的 PL/SQL 版本中改变吗?如果它可以改变,有没有办法强制评估我可以依赖的函数(不创建另一个变量并使用单独的赋值语句)?

【问题讨论】:

【参考方案1】:

是的。 PL/SQL 从左到右执行short circuit evaluation 的逻辑表达式。

【讨论】:

完美。正是我想要的! 我的谷歌“pl/sql 完整布尔评估”给了我完全相同的链接。 这是一个比我尝试过的更好的搜索:“PLSQL 强制评估”。谢谢!【参考方案2】:

如果它可以改变,有没有办法强制评估我可以依赖的函数(无需创建另一个变量并使用单独的赋值语句)?

如果您要求必须对函数进行评估,即使这样做在逻辑上是多余的,这意味着它执行的操作不是简单地返回 TRUE 或 FALSE,例如也许它会更新一张桌子。 PL/SQL 函数具有这样的“副作用”并不是很好的做法。

【讨论】:

一系列编辑功能。每个问题都会编辑消息并返回一个指示符是否应该跳过当前记录。跳过标志以 FALSE 开始,如果检查失败则设置为 TRUE。如果它通过任何特定检查,我不希望跳过标志重置为 FALSE。 您可以将这些函数替换为带有标志的 IN OUT 参数的过程。如果任何检查失败,程序会将标志设置为 TRUE,但如果没有检查失败,则将其置之不理: l_flag := FALSE; do_check1 (l_flag); do_check2 (l_flag); do_check3 (l_flag);【参考方案3】:

在文档中,它指出短路评估适用于 IF、CASE 和 CASE 表达式:我敢打赌,它也适用于您引用的示例,但在技术上并没有记录它这样做。可能值得就这种行为向 Oracle 提出罚单以确认它。

【讨论】:

【参考方案4】:

这被称为“短路评估”,它是大多数语言的规范,including PL/SQL。

【讨论】:

【参考方案5】:

它从左到右计算 OR 语句,从右到左计算 AND 语句。我没有找到任何关于它的文档。

【讨论】:

【参考方案6】:

“..and AND statements from right to left”到底是什么意思? 这是来自 oracle 文档=>

在以下示例中,请注意,当 valid 的值为 FALSE 时,无论 done 的值如何,整个表达式都会产生 FALSE:

有效并完成

您可以在以下示例中查看顺序:

声明 b1 布尔值; b2 布尔值;

功能检查 (v NUMBER) 返回布尔值 是 开始 DBMS_OUTPUT.put_line('内部检查:' || v); 返回真; 结束检查;

PROCEDURE outp (n VARCHAR2, p BOOLEAN) 是 开始 如果 p 那么 DBMS_OUTPUT.put_line (n || '为真'); 其他 DBMS_OUTPUT.put_line (n || '为假'); 结束如果; 结束; 开始 b1 := checkit (1) AND checkit (2); outp ('b1', b1); b2 := checkit (3) AND checkit (4); outp ('b2', b2); 结束;


内部检查:1 内部检查:2 b1 是真的 内部检查:3 内部检查:4 b2 是真的

【讨论】:

以上是关于PL/SQL 评估顺序的主要内容,如果未能解决你的问题,请参考以下文章

SQL 查询的 SELECT 子句中 Oracle PL/SQL 语句的延迟评估

PL/SQL 过程顺序

PL/SQL 异常以啥顺序引发?

匿名 pl/sql 块中的声明顺序

PL/SQL 过程的同步。如何保证一次只执行一个程序? [复制]

Oracle 构建顺序和 PL/SQL 包依赖关系