2011-03-02 29 views
2

我有一個Web表單,它允許用戶根據傳入進程的參數從Oracle表中搜索和編輯記錄。這是我的數據:Oracle nvl在哪裏顯示奇怪的結果?

CAE_SEC_ID SEC_CODE APPR_STATUS 
1   ABC1  100 
2   ABC2  100 
3   ABC3  101 
4   (null) 101 
5   (null) 102 
6   ABC4  103 

而這裏的where子句:

select foo 
    from bar 
where CAE_SEC_ID = NVL(p_cae_sec_id,CAE_SEC_ID) 
    and Upper(SEC_CODE) like '%' || Upper(NVL(p_sec_code,SEC_CODE)) || '%' 
    and APPR_STATUS = NVL(p_appr_status, APPR_STATUS) 

的參數使用NVL應該只返回匹配的記錄,如果任何參數有值,以及所有記錄,如果沒有的參數具有值。所有漂亮的標準,所以我想。但是,當我做一個沒有任何參數值的查詢時,查詢不會返回帶有空SEC_CODE的記錄,即只返回記錄1,2,3和6。上面的where子句不應該包含具有空SEC_CODE值的記錄嗎?

回答

4

不,它不應該。

數據庫中的SEC_CODE爲空,因此UPPER(SEC_CODE)爲空,因此它將在LIKE匹配或幾乎任何超出IS NULL的其他比較時失敗。從技術上講,這是一個UNKNOWN,而不是FALSE,但是不足以通過測試。

7

問題是表中的SEC_CODE值爲NULL。這意味着,UPPER(sec_code)爲NULL和你的第二個謂語簡化爲

and NULL LIKE '%%' 

就像NULL不等於任何東西,沒有不等於任何東西,它不喜歡什麼。最有可能的,你要像

and (Upper(SEC_CODE) like '%' || Upper(NVL(p_sec_code,SEC_CODE)) || '%' or 
    (sec_code is null and p_sec_code is null)) 

,將返回的每一行,如果P_SEC_CODE爲NULL,但仍然適用的過濾器,如果P_SEC_CODE非NULL。

3

表達式NULL = NULL的計算結果爲NULL,這不是true,所以這些行將不會返回。如果我理解正確的要求,你只需要過濾,如果一個參數爲null不同,所以我會改寫這樣的查詢,使過濾更加明確:

select foo from bar 
where (p_cae_sec_id is null or CAE_SEC_ID = p_cae_sec_id) 
and (p_sec_code is null or Upper(SEC_CODE) like '%' || Upper(p_sec_code) || '%') 
and (p_appr_status is null or APPR_STATUS = p_appr_status) 

設置p_sec_code參數設置爲null現在返回所有行,忽略SEC_CODE列中的值。

0

我們也可以寫出喬恩的查詢像

select foo from bar 
where (CASE WHEN p_cae_sec_id is null THEN 'Y' 
      WHEN CAE_SEC_ID = p_cae_sec_id THEN 'Y' 
        ELSE 'N' 
        END)='Y' 
and (CASE WHEN p_sec_code is null THEN 'Y' 
      WHEN Upper(SEC_CODE) like '%' || Upper(p_sec_code) || '%' THEN 'Y' 
        ELSE 'N' 
        END)='Y' 
and (CASE WHEN p_appr_status is null THEN 'Y' 
        WHEN APPR_STATUS = p_appr_status THEN 'Y' 
       ELSE 'N' 
       END)='Y' 

,使之具體和提高性能。

+0

有趣的是,你能否詳細說明爲什麼會提高性能? – 2011-03-05 18:13:16