Oracle 在PL\SQL中使用具有空值的变量的动态游标

Oracle 在PL\SQL中使用具有空值的变量的动态游标,oracle,plsql,oracle11g,Oracle,Plsql,Oracle11g,有人能帮我解决这个问题吗? 我有一个如下定义的游标: CURSOR c_cursorName ( paramA IN VARCHAR2, paramB IN VARCHAR2) IS SELECT tableA.id, tableA.name FROM tableA WHERE tableA.fieldA = paramA AND (paramB IS NULL OR tableA

有人能帮我解决这个问题吗? 我有一个如下定义的游标:

 CURSOR c_cursorName (
      paramA   IN VARCHAR2,
      paramB   IN VARCHAR2)
   IS
      SELECT tableA.id, tableA.name
        FROM tableA
       WHERE     tableA.fieldA = paramA
             AND (paramB IS NULL OR tableA.fieldB = paramB);
我为什么要这么做?因为我想在两种不同的情况下重用此游标:

  • 当我传递一个paramB值以返回tableA中的所有行时 其中fieldA等于paramA值,fieldB等于paramB
  • 当我不在paramB中传递任何值(
    null
    value)时,我想返回tableA中的所有行,其中fieldA等于paramA(我不关心fieldB) 问题是:当我在paramB中通过
    null
    时,我的解释计划会急剧增加,并且会出现性能问题

    实现这一点的简单方法是创建两个不同的游标,每种情况一个。但我正试图找到一个好的、聪明的解决方案,而不需要创建新的索引或游标

    有什么建议吗?

    你可以试试:

    cursor c_cursorname (parama in varchar2,
                         paramb in varchar2)
    is
    with results as (select tablea.id,
                            tablea.name,
                            tablea.fieldb
                     from   tablea
                     where  tablea.fielda = parama)
    select id, name
    from   results
    where  paramb is null
    union all
    select id, name
    from   results
    where  fieldb = paramb;
    
    Oracle应该能够根据paramb的值短路union all中运行的两个查询中的哪一个。

    您可以尝试:

    cursor c_cursorname (parama in varchar2,
                         paramb in varchar2)
    is
    with results as (select tablea.id,
                            tablea.name,
                            tablea.fieldb
                     from   tablea
                     where  tablea.fielda = parama)
    select id, name
    from   results
    where  paramb is null
    union all
    select id, name
    from   results
    where  fieldb = paramb;
    

    Oracle应该能够根据paramb的值短路union all中运行的两个查询中的哪一个。

    一个基于@Boniest的“独占union all”方法的稍加修改的解决方案:

    我不使用子查询来避免可能的物化,而是添加显式查询 检查paramb的NULL/notnull以始终仅执行UNION ALL的一部分

     SELECT tableA.id, tableA.name
            FROM tableA
           WHERE     tableA.fieldA = :parama
                 AND  :paramb IS NULL 
    UNION ALL
     SELECT tableA.id, tableA.name
            FROM tableA
           WHERE     tableA.fieldA = :parama
                 AND :paramb IS NOT NULL 
                 AND fieldb = :paramb
    
    我假设表A上有一个索引(fieldA,fieldB)

    这将导致下面的执行计划

    对于
    paramb为空
    fieldA上的索引范围扫描已完成

    对于
    paramb不为空
    fieldA上的索引范围扫描,fieldB已完成

    ---------------------------------------------------------------------------------------------
    | Id  | Operation                     | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT              |             |   101 |  4962 |     5  (40)| 00:00:01 |
    |   1 |  UNION-ALL                    |             |       |       |            |          |
    |*  2 |   FILTER                      |             |       |       |            |          |
    |   3 |    TABLE ACCESS BY INDEX ROWID| TABLEA      |   100 |  4900 |     3   (0)| 00:00:01 |
    |*  4 |     INDEX RANGE SCAN          | TABLEA_IDX1 |    40 |       |     2   (0)| 00:00:01 |
    |*  5 |   FILTER                      |             |       |       |            |          |
    |   6 |    TABLE ACCESS BY INDEX ROWID| TABLEA      |     1 |    62 |     2   (0)| 00:00:01 |
    |*  7 |     INDEX RANGE SCAN          | TABLEA_IDX1 |     1 |       |     1   (0)| 00:00:01 |
    ---------------------------------------------------------------------------------------------
    
    Query Block Name / Object Alias (identified by operation id):
    -------------------------------------------------------------
    
       1 - SET$1
       2 - SEL$1
       3 - SEL$1 / TABLEA@SEL$1
       4 - SEL$1 / TABLEA@SEL$1
       5 - SEL$2
       6 - SEL$2 / TABLEA@SEL$2
       7 - SEL$2 / TABLEA@SEL$2
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter(:PARAMB IS NULL)
       4 - access("TABLEA"."FIELDA"=TO_NUMBER(:PARAMA))
       5 - filter(:PARAMB IS NOT NULL)
       7 - access("TABLEA"."FIELDA"=TO_NUMBER(:PARAMA) AND "FIELDB"=TO_NUMBER(:PARAMB))
    

    基于@Boniest:

    我不使用子查询来避免可能的物化,而是添加显式查询 检查paramb的NULL/notnull以始终仅执行UNION ALL的一部分

     SELECT tableA.id, tableA.name
            FROM tableA
           WHERE     tableA.fieldA = :parama
                 AND  :paramb IS NULL 
    UNION ALL
     SELECT tableA.id, tableA.name
            FROM tableA
           WHERE     tableA.fieldA = :parama
                 AND :paramb IS NOT NULL 
                 AND fieldb = :paramb
    
    我假设表A上有一个索引(fieldA,fieldB)

    这将导致下面的执行计划

    对于
    paramb为空
    fieldA上的索引范围扫描已完成

    对于
    paramb不为空
    fieldA上的索引范围扫描,fieldB已完成

    ---------------------------------------------------------------------------------------------
    | Id  | Operation                     | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT              |             |   101 |  4962 |     5  (40)| 00:00:01 |
    |   1 |  UNION-ALL                    |             |       |       |            |          |
    |*  2 |   FILTER                      |             |       |       |            |          |
    |   3 |    TABLE ACCESS BY INDEX ROWID| TABLEA      |   100 |  4900 |     3   (0)| 00:00:01 |
    |*  4 |     INDEX RANGE SCAN          | TABLEA_IDX1 |    40 |       |     2   (0)| 00:00:01 |
    |*  5 |   FILTER                      |             |       |       |            |          |
    |   6 |    TABLE ACCESS BY INDEX ROWID| TABLEA      |     1 |    62 |     2   (0)| 00:00:01 |
    |*  7 |     INDEX RANGE SCAN          | TABLEA_IDX1 |     1 |       |     1   (0)| 00:00:01 |
    ---------------------------------------------------------------------------------------------
    
    Query Block Name / Object Alias (identified by operation id):
    -------------------------------------------------------------
    
       1 - SET$1
       2 - SEL$1
       3 - SEL$1 / TABLEA@SEL$1
       4 - SEL$1 / TABLEA@SEL$1
       5 - SEL$2
       6 - SEL$2 / TABLEA@SEL$2
       7 - SEL$2 / TABLEA@SEL$2
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter(:PARAMB IS NULL)
       4 - access("TABLEA"."FIELDA"=TO_NUMBER(:PARAMA))
       5 - filter(:PARAMB IS NOT NULL)
       7 - access("TABLEA"."FIELDA"=TO_NUMBER(:PARAMA) AND "FIELDB"=TO_NUMBER(:PARAMB))
    

    两种解决方案都很棒!但我有一个性能问题,因为我需要在这里处理实际表中的索引(当然,表A不存在)。谢谢两种解决方案都很棒!但我有一个性能问题,因为我需要在这里处理实际表中的索引(当然,表A不存在)。谢谢