2012-03-21 3 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; 

Я добавил 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. 

(Это не работает для BETWEEN условии, конечно).

+0

+1, использование переменных привязки. – Ollie

+0

Что вы думаете об этой формулировке? (Копировать на жаба читать) ВЫБОР loc.RMV_REMI_VIRTUALE_COD, loc.LOC_DATA_VER_FIN ОТ ENI_SAG_TSF_LOCALITA_DEF LOC где 1 = 1 и (LOC.LOC_LOCALITA_COD =: P_LOC_LOCALITA_COD ИЛИ: P_LOC_LOCALITA_COD IS NULL) И (loc.COMB_ISTAT_COD =: P_ISTAT_CITTA ИЛИ : P_ISTAT_CITTA IS NULL) AND (LOC.PLAY_PLAYER_COD =: P_PLAY_PLAYER_COD ИЛИ LOC.PLAY_PLAYER_COD IS NULL) AND (TO_TIMESTAMP (: P_LOC_DATA, 'DD/MM/YYYY HH24: MI: SS.FF3') МЕЖДУ LOC.LOC_DATA_VER_INI И LOC .LOC_DATA_VER_FIN ИЛИ: P_LOC_DATA IS NULL) – Revious

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

Надеется, что это помогает ...

Смежные вопросы