sql - 游标的替代品

标签 sql oracle plsql

我有一个函数,每次调用都会改变它的值。我想在查询中多次使用这个值,但我不想多次执行它,因为我想要第一次调用的值。我试过了:

SELECT RESULT value1,
       RESULT value2,
       RESULT value3
  FROM (SELECT function_invocation() RESULT
          FROM dual);

但是每个 VALUE 列都给了我不同的值,这意味着该函数被多次调用。

另一种方法是编写游标,但我想知道是否可以使用纯 SQL。

最佳答案

有一些技巧可以防止 Oracle 不必要地重新执行函数。这个话题很难,因为 99.9% 的时间我们都依赖 Oracle 自动重写查询以优化运行。停止这些优化不应该是一项常见的任务。

理论上,没有办法保证声明性 SQL 语句的操作顺序。在实践中,有两种简单的技术可以帮助防止函数重新运行:标量子查询缓存和 ROWNUM .

首先,让我尝试重现该问题。单个值引用返回三个不同的数字。

create or replace function function_invocation return number is
begin
    return dbms_random.value;
end;
/

SELECT RESULT value1,
       RESULT value2,
       RESULT value3
  FROM (SELECT function_invocation() RESULT
          FROM dual);

VALUE1   VALUE2   VALUE3
------   ------   ------
0.3089   0.7103   0.2885

重新编写查询以使用标量子查询似乎没有必要,但这种形式使 Oracle 能够使用标量子查询缓存,这是 Oracle 用来避免重新运行代码的优化技术。现在三列返回相同的值。
select result value1, result value1, result value1
from
(
    select (select function_invocation() from dual) result from dual
);

VALUE1   VALUE2   VALUE3
------   ------   ------
0.2450   0.2450   0.2450

或者,我们可以通过添加 ROWNUM 来防止优化转换。伪列:
SELECT RESULT value1,
       RESULT value2,
       RESULT value3
  FROM (SELECT function_invocation() RESULT, rownum
          FROM dual);

VALUE1   VALUE2   VALUE3
------   ------   ------
0.1678   0.1678   0.1678

这些技术在实践中效果很好,可以使结果看起来正确。但是,该函数可能会在执行之前 secret 运行一段时间。额外的运行用于解析和缓存,不会影响结果。但是,如果您有一个只能运行一次的带有副作用的函数,那么您必须跳过一些额外的环节。

关于sql - 游标的替代品,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55436763/

相关文章:

sql - 省略日期中的毫秒数

mysql - SQL 计数等于 1 个值的记录,并对其余的进行计数和分组

oracle - 顶点始终执行验证

oracle - SQL Developer 不显示 dbms_output

java - 使用带有 boolean IN 参数的 CallableStatement 在 Java 中调用 Oracle PL/SQL 过程会产生 PLS-00306 oracle 错误 :

sql - Postgresql 在函数内的查询上使用 VARIADIC

php - PDO 准备好的语句更新不起作用

java - 关于从 Oracle Forms UI 迁移到 JSP 的建议

oracle - 如何在 oracle regexp_like() 中进行负向前瞻, '?!' 不起作用

xml - 尝试检测 PL/SQL 过程中的非法 XML 字符