2016-05-18 12 views
0

誰でもこの問題を解決できますか?PL SQLのヌル値を持つ変数を使用する動的カーソル

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); 

は、なぜ私はこれをやっている: 私はこのように定義されたカーソルを持っていますか?私は2つの異なるケースで、このカーソルを再利用したいので:私はFIELDAがparamA値に等しく、FIELDBがparamBに等しいにtableA 内のすべての行を返すためにparamB値を渡すとき

  1. 私はparamB(null値)に値を渡さず、fieldAがparamAと単純に等しい(そしてfieldBについては気にしません)tableAのすべての行を返したいと思います。

問題:paramBにnullを渡すと、私の説明計画が大幅に増加し、パフォーマンス上の問題が発生します。

これを行う簡単な方法は、それぞれのケースごとに1つずつ、2つの異なるカーソルを作成することです。しかし、私は新しいインデックスや新しいカーソルを作成する必要なく、巧妙なソリューションを見つけようとしています。

提案がありますか?

答えて

3

あなたは試みることができる:

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の値に基づいて組合内の2つのクエリの短絡にできるはずです。

3

Aはわずか@Boniestから「排他的な労働組合のすべての」アプローチに基づいたソリューションを修正:

私はそれの可能マテリアを避けるために、サブクエリを使用していないと私はのNULL NULL/NOTに明示的な チェックを追加UNION ALLの1つの部分だけを常に実行するようにします。

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(フィールドA、フィールドB)のインデックスを仮定します。

これは、以下の実行計画につながります。 fieldA, fieldBparamb is NOT NULL索引レンジ・スキャンが行われているためfieldAparamb is NULL索引レンジ・スキャンの場合

は、

が行われます。

--------------------------------------------------------------------------------------------- 
| 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/[email protected]$1 
    4 - SEL$1/[email protected]$1 
    5 - SEL$2 
    6 - SEL$2/[email protected]$2 
    7 - SEL$2/[email protected]$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)) 
+0

両方のソリューションが素晴らしいです!しかし、ここではREALテーブルのインデックスを使用して再生する必要があるため、パフォーマンスに関する問題が1つあります(tableAは存在しません)。ありがとう! – milheiros

関連する問題