PL/SQL - where 子句中的可选条件 - 没有动态 sql?

2024-01-03

我有一个疑问,并非所有条件都是必要的。以下是使用所有条件时的示例:

select num
from (select distinct q.num
       from cqqv q
       where q.bcode = '1234567' --this is variable
             and q.lb = 'AXCT' --this is variable
             and q.type = 'privt' --this is variable
             and q.edate > sysdate - 30 --this is variable
       order by dbms_random.value()) subq
where rownum <= 10; --this is variable

零件标记为--this is variable是那些不同的部分!如果未指定条件,则没有默认值。例如,如果输入为 q.type 指定“*”(但其他所有内容保持不变),则查询应匹配 type 的所有内容,并执行为:

select num
from (select distinct q.num
       from cqqv q
       where q.bcode = '1234567' --this is variable
             and q.lb = 'AXCT' --this is variable
             --and q.type = 'privt' --this condition ignored because of "type=*" in input
             and q.edate > sysdate - 30 --this is variable
       order by dbms_random.value()) subq
where rownum <= 10; --this is variable

我知道可以使用动态 sql 动态构建此查询,但我想知道这可能会导致什么样的性能问题,以及是否有更好的方法来做到这一点。


虽然你可以这样做...

select num
from (select distinct q.num
       from cqqv q
       where 1=1
             and (:bcode is null or q.bcode = :bcode)
             and (:lb is null or q.lb = :lb)
             and (:type is null or q.type = :type)
             and (:edate is null or q.edate > :edate - 30)
       order by dbms_random.value()) subq
where rownum <= :numrows

...使用动态 SQL 的性能通常是better,因为它将生成更有针对性的查询计划。在上面的查询中,Oracle无法判断是在bcode还是lb上使用索引,还是在type或edate上使用索引,并且可能每次都会执行全表扫描。

当然,你must在动态查询中使用绑定变量,而不是将文字值连接到字符串中,否则性能(以及可扩展性和安全性)将受到影响very bad.

需要明确的是,我想到的动态版本将像这样工作:

declare
    rc sys_refcursor;
    q long;
begin
    q := 'select num
    from (select distinct q.num
           from cqqv q
           where 1=1';

    if p_bcode is not null then
        q := q || 'and q.bcode = :bcode';
    else
        q := q || 'and (1=1 or :bcode is null)';
    end if;

    if p_lb is not null then
        q := q || 'and q.lb = :lb';
    else
        q := q || 'and (1=1 or :lb is null)';
    end if;

    if p_type is not null then
        q := q || 'and q.type = :type';
    else
        q := q || 'and (1=1 or :type is null)';
    end if;

    if p_edate is not null then
        q := q || 'and q.edate = :edate';
    else
        q := q || 'and (1=1 or :edate is null)';
    end if;

    q := q || ' order by dbms_random.value()) subq
    where rownum <= :numrows';

    open rc for q using p_bcode, p_lb, p_type, p_edate, p_numrows;
    return rc;
end;

这意味着查询结果will是“sargable”(对我来说这是一个新词,我必须承认!),因为生成的查询运行将是(例如):

select num
from (select distinct q.num
       from cqqv q
       where 1=1
             and q.bcode = :bcode
             and q.lb = :lb
             and (1=1 or :type is null)
             and (1=1 or :edate is null)
       order by dbms_random.value()) subq
where rownum <= :numrows

不过,我承认在此示例中可能需要最多 16 次硬解析。使用本机动态 SQL 时需要“and :bv is null”子句,但可以通过使用 DBMS_SQL 来避免。

注意:使用(1=1 or :bindvar is null)Michal Pravda 在评论中建议当绑定变量为 null 时,因为它允许优化器消除该子句。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PL/SQL - where 子句中的可选条件 - 没有动态 sql? 的相关文章

  • WHERE IN 条件不接受字符串值

    我正在动态构造一个带有名称的字符串用户数据在 PL Sql 过程中通过附加用户名 单引号 和逗号 的形式 abc123 xyz456 pqr789 但是当我将此字符串传递给 SELECT 语句的 WHERE IN 条件时 SELECT FR
  • PL/SQL 过程成功完成但没有显示任何内容

    我有以下过程代码 create or replace PROCEDURE Ventas cliente p DNI IN CHAR IS CURSOR c pedidos clientes IS SELECT FROM Pedidos ve
  • 当网站停止时,Oracle 数据提供程序会固定 IIS 工作进程

    我们在 Oracle 11g 第 2 版中遇到了一个严重的问题 其中 w3wp 进程接管了整个处理器核心 并且调试显示 Oracle 数据提供程序无限地抛出 ThreadAbortException 开发人员通过执行以下操作发现了此问题 1
  • 无法在 .NET 中加载 Oracle.DataAccess 的文件或程序集

    当我尝试运行一个简单的程序来访问 oracle 时 我收到此消息 无法加载文件或程序集 Oracle DataAccess 版本 2 111 7 20 文化 中性 PublicKeyToken 89b483f429c47342 或其依赖项之
  • 如何从 TOAD for Oracle 执行函数并将结果绑定到数据网格

    我有一个函数 它将 pl sql 对象的 VARRAY 作为其参数之一 如何执行此存储过程并将其返回的结果集绑定到 TOAD for Oracle 中的数据网格 经过一番搜索后 我找到了自己问题的答案 假设您的 varray 类型称为 va
  • 递归 SQL 给出 ORA-01790

    使用 Oracle 11g 第 2 版 以下查询给出 ORA 01790 表达式必须与相应表达式具有相同的数据类型 with intervals time interval AS select trunc systimestamp from
  • Oracle 9i:同义词表不存在?

    我创建了一个包 其中包含一个存储过程 我计划从单独的应用程序调用该存储过程 存储过程将返回架构中所有视图和表的排序列表 为此 它对 DBA TABLES 和 DBA VIEWS 同义词执行简单的选择 如下所示 CREATE OR REPLA
  • 替换 Oracle 包的一部分

    我需要修改包内的一个过程 我需要接触声明和实施 由于我正在维护每次修改的补丁文件 因此我希望更改最小化 我可以仅使用更改的过程更新包 如果是 如何更新 还是需要提供完整的包定义和实现 您需要替换整个包规范和主体 您不能仅对包的一部分进行操作
  • 分层查询

    我希望我能够解释困扰我的问题 我有以下分层数据集 这只是 34K 记录的子集 PARENT ID CHILD ID EXAM TUDA12802 TUDA12982 N TUDA12982 TUDA12984 J TUDA12984 TUD
  • 通过 Oracle 的数据库链接运行 SQL Server 存储过程

    参考如何通过数据库链接执行 Oracle 存储过程 https stackoverflow com questions 240788 how to execute an oracle stored procedure via a datab
  • Oracle:如何确定“AFTER ALTER”触发器中对象的新名称?

    假设我有一个AFTER ALTER在我的 Oracle 数据库上触发并重命名一些数据库对象 ALTER RENAME TO 在触发器中 我如何确定new数据库对象的名称 看来ORA DICT OBJ OWNER ORA DICT OBJ N
  • Delphi 5 中的 Oracle 数据库连接

    我正在使用 Delphi 5 版本 我想连接到 Oracle 数据库 我有 TDatabase 组件 我不知道如何通过 Delphi 连接到数据库 请提供连接数据库的步骤 谢谢 The TDatabase http docwiki emba
  • SQL 国家字符 (NCHAR) 数据类型的真正用途是什么?

    也CHAR CHARACTER and VARCHAR CHARACTER VARYING SQL 提供了NCHAR NATIONAL CHARACTER and NVARCHAR NATIONAL CHARACTER VARYING 类型
  • 在 SELECT IN 中使用 Oracle 参数时出现问题

    我在将一串数字插入sql查询时遇到问题 SELECT FROM tablename a WHERE a flokkurid IN 3857 3858 3863 3285 ORDER BY sjodategund rodun or SELEC
  • Oracle 语法 - 我们是否必须在新旧语法之间进行选择?

    我在一个由大约 8 名开发人员组成的团队中负责大约 1 000 000 行源代码的代码库 我们的代码基本上是一个使用 Oracle 数据库的应用程序 但代码随着时间的推移而不断发展 我们有大量九十年代中期的源代码 团队中就我们用于查询 Or
  • OracleDataSource.getConnection 是线程安全的吗?

    我以为找到这个答案很容易 但并不是那么容易 有谁知道 OracleDataSource getConnection 方法是否是线程安全的 我不是指它返回的 Connection 对象 而是指 getConnection 本身的调用 具体来说
  • ora-04091 表正在发生变化-

    我正在使用一个函数来比较表 1 和表 2 中的所有列并返回 Y 或 N 在此基础上 我将更新我的表 1 但是当我运行合并语句时 它显示错误 ora 04091 Table1 正在发生变化 触发器 函数可能看不到它 我怎样才能解决这个问题 C
  • 在 Hibernate 中创建 UPDATE RETURNING 查询

    在 Oracle 中 我们可以创建一个更新查询 该查询将使用 RETURNING 子句返回更新的记录 Hibernate中有类似的功能吗 除了数据库生成的值之外 Hibernate 显然不需要返回更新的实例 因为对象传递给Session s
  • Windows 上良好的 Oracle 数据库开发和管理工具 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找像 sql server management studio 这样的 Oracle 数据库管理工具 我在互联网上搜索并在以下链接
  • 循环预定义值

    有没有办法在 oracle 中执行 for every 如下所示 begin for VAR in 1 2 5 loop dbms output put line The value VAR end loop end 我知道你可以这样做 b

随机推荐