2012-03-21 46 views
1

看看下面的查詢。我怎樣才能以更可讀的方式編寫它? 我想,以減少IF甲骨文: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 2012-03-21 15:20:24

+1

空白和空格? – Ben 2012-03-21 15:29:02

+0

我正確地看到空格。你怎麼看他們? – Revious 2012-03-21 15:35:50

回答

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

對於性能不成問題的小表,這可能是正確的。潛在的問題是沒有明顯的訪問路徑,所以它可能總是以全表掃描的方式完成。使用動態查詢,根據用戶輸入的條件生成最佳查詢。 – 2012-03-21 17:22:39

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; 

我增加了else子句,因爲本地動態SQL綁定變量的數量在聲明中有等待修復。如果使用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 ||位。

如果要添加很多類似的情況,你可以換邏輯的功能,如:

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. 

(這並不爲工作之間,當然條件)。

+0

+1,使用綁定變量。 – Ollie 2012-03-21 15:44:20

+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爲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')LOC.LOC_DATA_VER_INI AND LOC .LOC_DATA_VER_FIN OR:P_LOC_DATA IS NULL) – Revious 2012-03-21 17:06:48

2

「更具可讀性」是有點主觀的,但一對夫婦的選擇,如果你不喜歡的IF THEN塊:

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

希望它可以幫助...