2012-01-27 64 views
1

我目前在Java中有一個準備好的語句,它在我的查詢的WHERE子句中使用以下SQL語句,但是我想重新寫入一個函數來限制用戶參數傳遞給它並可能使其更有效。在包含空搜索的where子句中使用函數

(
    (USER_PARAM2 IS NULL AND 
    (COLUMN_NAME = nvl(USER_PARAM1, COLUMN_NAME) OR 
     (nvl(USER_PARAM1, COLUMN_NAME) IS NULL) 
    ) 
) 
    OR 
    (USER_PARAM2 IS NOT NULL AND COLUMN_NAME IS NULL) 
) 

USER_PARAM1和USER_PARAM2被用戶傳遞到準備好的語句中。 USER_PARAM1表示應用程序用戶想要搜索此特定COLUMN_NAME的內容。如果用戶不包含此參數,則它將默認爲NULL。 USER_PARAM2是我允許用戶在此COLUMN_NAME上僅搜索NULL值的方式。此外,我有一些服務器邏輯,如果用戶傳入,則將USER_PARAM2設置爲「true」;如果未由用戶指定,則爲NULL。

預期的行爲是,如果聲明USER_PARAM2,則只返回NULL的COLUMN_NAME值。如果未聲明USER_PARAM2並聲明瞭USER_PARAM1,則只返回COLUMN_NAME = USER_PARAM1。如果沒有聲明用戶參數,則返回所有行。

任何人都可以幫我解決這個問題嗎? 在此先感謝...

編輯: 只是爲了澄清這是我當前查詢的外觀(沒有其他WHERE子句中陳述..)

SELECT * 
FROM TABLE_NAME 
WHERE (
    (USER_PARAM2 IS NULL AND 
    (COLUMN_NAME = nvl(USER_PARAM1, COLUMN_NAME) OR 
     (nvl(USER_PARAM1, COLUMN_NAME) IS NULL) 
    ) 
) 
    OR 
    (USER_PARAM2 IS NOT NULL AND COLUMN_NAME IS NULL) 
) 

...這是我願意喜歡去......

SELECT * 
FROM TABLE_NAME 
WHERE customSearchFunction(USER_PARAM1, USER_PARAM2, COLUMN_NAME) 

編輯#2: 好了,另一個同事幫我這...

CREATE OR REPLACE function searchNumber (pVal IN NUMBER, onlySearchForNull IN CHAR, column_value IN NUMBER) 
    RETURN NUMBER 
IS 
BEGIN 
    IF onlySearchForNull IS NULL THEN 
    IF pVal IS NULL THEN 
     RETURN 1; 
    ELSE 
     IF pVal = column_value THEN 
     RETURN 1; 
     ELSE 
     RETURN 0; 
     END IF; 
    END IF; 
    ELSE 
    IF column_value IS NULL THEN 
     RETURN 1; 
    ELSE 
     RETURN 0; 
    END IF; 
    END IF; 
END; 

...這似乎在我的初步試驗工作..

SELECT * 
FROM TABLE_NAME 
WHERE 1=searchNumber(USER_PARAM1, USER_PARAM2, COLUMN_NAME); 

...我與它唯一的問題是 1)可能的性能問題VS複雜的SQL語句,我開始用。 2)我將不得不爲每種數據類型創建類似的函數。 但是,後者對我來說不是什麼問題。

編輯#3 2012.02.01

所以我們結束了我在下面選擇的解決方案去,在使用功能爲基礎的方法,其中代碼/查詢清潔勝過性能。我們發現基於函數的方法比使用純SQL要差6倍左右。

感謝大家爲偉大的輸入大家!

編輯#4 2012.02.14

所以回過頭來看,我注意到,在@爲@ danihp的溶液的澄清度應用虛擬表的概念艾倫的解決方案給出了清晰和性能方面非常不錯的整體解決方案。這裏是我現在有的

WITH params AS (SELECT user_param1 AS param, user_param2 AS param_nullsOnly FROM DUAL) 
SELECT * 
FROM table_name, params p 
WHERE (nvl(p.param_nullsOnly, p.param) IS NULL     --1) 
     OR p.param_nullsOnly IS NOT NULL AND column_name IS NULL --2) 
     OR p.param IS NOT NULL AND column_name = p.param   --3) 
     ) 
-- 1) Test if all rows should be returned 
-- 2) Test if only NULL values should be returned 
-- 3) Test if param equals the column value 

再次感謝您的建議和意見!

+0

爲什麼更改爲一個函數?原生SQL雖然可能看起來很亂,但肯定會表現更好。 – 2012-01-27 17:49:25

+0

如果你真的想要一個函數,那麼你的「customSearchFunction」必須返回一個varchar2值(例如S/N)。而你的位置將在WHERE customSearchFunction(USER_PARAM1,USER_PARAM2,COLUMN_NAME)='S' – 2012-01-27 17:54:40

+1

正如你所說的使用一個函數可能在評估你的語句時強制進行全表掃描。如果它是一個小桌子(或小桌子的連接),這可能無關緊要,但如果它是一張大桌子,表演可能會有很多不足之處。因人而異。 – 2012-01-27 17:59:11

回答

2

有一個簡單的方法來傳遞您的參數只有一次,並根據需要引用它們多次,使用通用表表達式:

WITH params AS (SELECT user_param1 AS up1, user_param2 AS up2 FROM DUAL) 
SELECT * 
FROM table_name, params p 
WHERE ((p.up2 IS NULL 
     AND (column_name = NVL(p.up1, column_name) 
       OR (NVL(p.up1, column_name) IS NULL))) 
     OR (p.up2 IS NOT NULL AND column_name IS NULL)) 

實際上,您正在創建一個虛擬表,其中列是您的參數,並且只填充一行。

方便的是,這也確保您的所有參數都收集在同一個地方,並且可以以任意順序指定(與自然出現在查詢中的順序相反)。

這對於基於功能的方法有一些很大的優點。首先,這不會阻止使用索引(正如@Bob Jarvis指出的那樣)。其次,這將查詢的邏輯保留在查詢中,而不是隱藏在函數中。

+0

感謝!我真的很喜歡這種方法,結合速度和消除冗餘參數。 – hypno7oad 2012-01-31 15:32:16

2

我不知道如果我的方法有更多的表現,但它有最好的可讀性:

發送2個a​​dditionals參數查詢,可以重新編寫類似的查詢:

where 
(P_ALL_RESULTS is not null 
    OR 
    P_ONLY_NULLS is not null AND COLUMN_NAME IS NULL 
    OR 
    P_USE_P1 is not null AND COLUMN_NAME = USER_PARAM1 
) 

免責聲明:以前回答OP的問題澄清

+1

最後一個條件應爲:P_USE_P1不爲空AND COLUMN_NAME = USER_PARAM1 – 2012-01-27 18:00:00

+0

@BD,修正,謝謝。 – danihp 2012-01-27 18:08:22

+0

免責聲明:在OP問題澄清前回答。 – danihp 2012-01-27 18:09:37