2012-03-21 11 views
1

次のクエリを見てください。どのように私はそれをより読みやすい方法で書くことができますか? 私はまあ、私は常に、バインド変数を使用するコードではなく、値の連結読みやすくを見つける(そして、それははるかに良い習慣です)IFOracle:リラックスできる条件付きのPLSQLクエリ - 実現するためのエレガントな方法

vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 '; 
    IF P_LOC_LOCALITA_COD IS NOT NULL THEN 
    vSQL := vSQL||' AND LOC.LOC_LOCALITA_COD = '''||P_LOC_LOCALITA_COD||''' '; 
    END IF; 
    IF P_ISTAT_CITTA IS NOT NULL THEN 
    vSQL := vSQL||' AND loc.COMB_ISTAT_COD = '''||P_ISTAT_CITTA||''' '; 
    END IF; 
    IF P_PLAY_PLAYER_COD IS NOT NULL THEN 
    vSQL := vSQL||' AND LOC.PLAY_PLAYER_COD = '''||P_PLAY_PLAYER_COD||''' '; 
    END IF; 
    IF P_LOC_DATA IS NOT NULL THEN 
    vSQL := vSQL||' AND TO_TIMESTAMP ('''||P_LOC_DATA||''' , ''DD/MM/YYYY HH24:MI:SS.FF3'') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN '; 
    END IF; 
+0

myBatisを使用する場合は、条件付きSQLを使用してクエリを実装できます。 – DwB

+1

空白とスペース? – Ben

+0

空白が正しく表示されます。どのようにそれらを見ますか? – Revious

答えて

0

あなたの答えを読むこの製法が見つかりました。あなたはそれについてどう思いますか?

SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN 
    FROM ENI_SAG_TSF_LOCALITA_DEF loc 
WHERE 1 = 1 
     AND (LOC.LOC_LOCALITA_COD = :P_LOC_LOCALITA_COD OR :P_LOC_LOCALITA_COD IS NULL) 
     AND (loc.COMB_ISTAT_COD = :P_ISTAT_CITTA OR :P_ISTAT_CITTA IS NULL) 
     AND (LOC.PLAY_PLAYER_COD = :P_PLAY_PLAYER_COD OR LOC.PLAY_PLAYER_COD IS NULL) 
     AND (TO_TIMESTAMP (:P_LOC_DATA, 'DD/MM/YYYY HH24:MI:SS.FF3') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN OR :P_LOC_DATA IS NULL) 
+2

パフォーマンスに問題がない小さなテーブルの場合は、問題ありません。潜在的な問題は、明白なアクセス・パスがないことです。そのため、おそらく常にフル・テーブル・スキャンとして実行されることになります。動的クエリでは、ユーザが入力した基準に従って最適なクエリが生成されます。 –

4

の使用量を削減したいと思います。あなたは、SQLを実行する方法を言うことはありませんが、REF CURSORと仮定すると、あなたはこのようにそれを行うことができます:

vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 '; 
    IF P_LOC_LOCALITA_COD IS NOT NULL THEN 
    vSQL := vSQL||' AND LOC.LOC_LOCALITA_COD = :P_LOC_LOCALITA_COD '; 
    ELSE 
    vSQL := vSQL||' AND (1=1 OR :P_LOC_LOCALITA_COD IS NULL)'; 
    END IF; 
    IF P_ISTAT_CITTA IS NOT NULL THEN 
    vSQL := vSQL||' AND loc.COMB_ISTAT_COD = :P_ISTAT_CITTA '; 
    ELSE 
    vSQL := vSQL||' AND (1=1 OR :P_ISTAT_CITTA IS NULL)'; 
    END IF; 
    IF P_PLAY_PLAYER_COD IS NOT NULL THEN 
    vSQL := vSQL||' AND LOC.PLAY_PLAYER_COD = :P_PLAY_PLAYER_COD '; 
    ELSE 
    vSQL := vSQL||' AND (1=1 OR :P_PLAY_PLAYER_COD IS NULL)'; 
    END IF; 
    IF P_LOC_DATA IS NOT NULL THEN 
    vSQL := vSQL||' AND TO_TIMESTAMP (:P_LOC_DATA, ''DD/MM/YYYY HH24:MI:SS.FF3'') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN '; 
    ELSE 
    vSQL := vSQL||' AND (1=1 OR :P_LOC_DATA IS NULL)'; 
    END IF; 

    OPEN refcur FOR vSQL USING P_LOC_LOCALITA_COD, P_ISTAT_CITTA, P_PLAY_PLAYER_COD, P_LOC_DATA; 

文のバインド変数の数が持っている固有の動的SQLのためので、私はELSE句を追加しました固定する。 DBMS_SQLパッケージを使用する場合は、その必要はありません。

vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 '; 
    || CASE WHEN P_LOC_LOCALITA_COD IS NOT NULL THEN 
       ' AND LOC.LOC_LOCALITA_COD = :P_LOC_LOCALITA_COD ' 
      ELSE 
       ' AND (1=1 OR :P_LOC_LOCALITA_COD IS NULL)' 
      END 
    || CASE WHEN P_ISTAT_CITTA IS NOT NULL THEN 
       ' AND loc.COMB_ISTAT_COD = :P_ISTAT_CITTA ' 
      ELSE 
       ' AND (1=1 OR :P_ISTAT_CITTA IS NULL)' 
      END 
... etc. 

はもちろん、あなたが今、代わりにケースを持っていますが、少なくとも、あなたはすべての vSQL := vSQL ||ビットを失う:

のIFを避けるためとして、あなたはこれを行うことができます。

あなたはあなたのような機能のロジックをラップすることができ、同様の条件の多くを追加する場合:

vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 '; 
    || and_condition ('LOC.LOC_LOCALITA_COD', 'BV1', P_LOC_LOCALITA_COD) 
    || and_condition ('loc.COMB_ISTAT_COD', 'BV2', P_ISTAT_CITTA) 
    ... etc. 

(それは当然のBETWEEN条件では動作しません)。あなたはIF THENブロックである好きではない場合

+0

+1、バインド変数の使用。 – Ollie

+0

この処方についてどう思いますか? (:P_LOC_LOCALITA_COD OR:P_LOC_LOCALITA_COD IS NULL LOC.LOC_LOCALITA_COD =) AND(loc.COMB_ISTAT_COD =:P_ISTAT_CITTA OR 1 = 1 とENI_SAG_TSF_LOCALITA_DEFのLOC FROM(読むためヒキガエル上のコピー) SELECT loc.RMV_REMI_VIRTUALE_COD、loc.LOC_DATA_VER_FIN :P_ISTAT_CITTA IS NULL) AND(LOC.PLAY_PLAYER_COD =:P_PLAY_PLAYER_CODまたはLOC.PLAY_PLAYER_CODがNULL) AND(TO_TIMESTAMP(:P_LOC_DATA、 'DD/MM/YYYY HH24:MI:SS.FF3')LOC.LOC_DATA_VER_INIおよびLOC間.LOC_DATA_VER_FIN OR:P_LOC_DATA IS NULL) – Revious

2

「より読みは」少し主観が、オプションのカップルです:

vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 '; 

vSQL := vSQL|| 
     NVL2(P_LOC_LOCALITA_COD, 
      ' AND LOC.LOC_LOCALITA_COD = '''||P_LOC_LOCALITA_COD||''' ', 
       NULL); 

vSQL := vSQL|| 
     NVL2(P_ISTAT_CITTA, 
       ' AND loc.COMB_ISTAT_COD = '''||P_ISTAT_CITTA||''' ', 
       NULL); 

vSQL := vSQL|| 
     NVL2(P_PLAY_PLAYER_COD, 
       ' AND LOC.PLAY_PLAYER_COD = '''||P_PLAY_PLAYER_COD||''' ', 
       NULL); 

vSQL := vSQL|| 
     NVL2(P_LOC_DATA, 
       ' AND TO_TIMESTAMP ('''||P_LOC_DATA||''' , ''DD/MM/YYYY HH24:MI:SS.FF3'') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN ', 
       NULL); 

または

vSQL := ' SELECT loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN FROM ENI_SAG_TSF_LOCALITA_DEF loc WHERE 1=1 ' 
     ||NVL2(P_LOC_LOCALITA_COD, 
       ' AND LOC.LOC_LOCALITA_COD = '''||P_LOC_LOCALITA_COD||''' ', 
       NULL) 
     ||NVL2(P_ISTAT_CITTA, 
       ' AND loc.COMB_ISTAT_COD = '''||P_ISTAT_CITTA||''' ', 
       NULL) 
     ||NVL2(P_PLAY_PLAYER_COD, 
       ' AND LOC.PLAY_PLAYER_COD = '''||P_PLAY_PLAYER_COD||''' ', 
       NULL) 
     ||NVL2(P_LOC_DATA, 
       ' AND TO_TIMESTAMP ('''||P_LOC_DATA||''' , ''DD/MM/YYYY HH24:MI:SS.FF3'') BETWEEN LOC.LOC_DATA_VER_INI AND LOC.LOC_DATA_VER_FIN ', 
       NULL); 

はそれが役に立てば幸い...

関連する問題