sql語句的case-end語句的疑似bug經歷

給客服部做客戶分級服務的客戶信息設置。要求根據客戶歷史積分、客戶投資成本兩個指標對客戶進行評級。客戶級別分爲4級:
    級別1-integral介於[0, 8188]或者investcost介於[ 0, 50000]
    級別2-integral介於[8188, 15888]或者investcost介於[ 50000, 500000]
    級別3-integral介於[15888, 98888]或者investcost介於[ 500000, 100000]
    級別4-integral介於[15888, 無窮大]或者investcost介於[ 100000, 無窮大]

沒仔細細想,將兩個表聯查,並根據integral和investcost兩個字段,生成一個levelsign字段。sql代碼如下:
CREATE TABLE tcustlevel AS
SELECT t.customerid, --t.customertypesign, t.customerlevelsign, t.customerintegral, nvl(t2.investcost, 0) investcost,
    (case
    when (t.customerintegral >= 0 AND t.customerintegral < 8188) OR (nvl(t2.investcost, 0) >= 0 AND nvl(t2.investcost, 0) < 50000)
        then '1'
    when (t.customerintegral >= 8188 AND t.customerintegral < 15888) OR (nvl(t2.investcost, 0) >= 50000 AND nvl(t2.investcost, 0) < 500000)
        then '2'
    when (t.customerintegral >= 15888 AND t.customerintegral < 98888) OR (nvl(t2.investcost, 0) >= 500000 AND nvl(t2.investcost, 0) < 1000000)
        then '3'
    when (t.customerintegral >= 98888) OR (nvl(t2.investcost, 0) >= 1000000)
        THEN '4'
    end) levelsign--, t.*, t2.*
--SELECT COUNT(*)    
FROM tcustintegral t, tcustcost t2
WHERE 1 = 1
AND t.customerid = t2.customerid(+);
後來實際用到levelsign數據後,才發現,這樣寫存在一個大bug!!!比如當(integral, investcost) =(15234,792561)時,levelsign應該取3,但結果取值爲2。

突然發現以前解決過類似的問題,這是由於case-end的順序執行和A or B的條件判斷兩個因素造成的。case-end順序執行子句中的每一個條件,滿足則輸出結果並結束後續子句的執行,否則執行下一個子句(即判斷條件)。按照上面給定的值,在第2個子句(t.customerintegral >= 8188 AND t.customerintegral < 15888) OR (nvl(t2.investcost, 0) >= 50000 AND nvl(t2.investcost, 0) < 500000)時條件爲真,所以輸出'2',忽略後續餘下子句中的判斷條件。

鑑於本問題中的情況,耍了個小伎倆,將執行順序顛倒,就可以避免錯誤,輸出正確結果,唯一的缺憾是非最優美的解決方案(即萬一後來人維護該段代碼時,改變了子句順序,則又會出錯了)。所以只好在該段代碼頭上加上了一段提示性的註釋,特別提醒注意。
CREATE TABLE tcustlevel AS
SELECT t.customerid, --t.customertypesign, t.customerlevelsign, t.customerintegral, nvl(t2.investcost, 0) investcost,
    (case
    when (t.customerintegral >= 98888) OR (nvl(t2.investcost, 0) >= 1000000)
        THEN '4'
    when (t.customerintegral >= 15888 AND t.customerintegral < 98888) OR (nvl(t2.investcost, 0) >= 500000 AND nvl(t2.investcost, 0) < 1000000)
        then '3'
    when (t.customerintegral >= 8188 AND t.customerintegral < 15888) OR (nvl(t2.investcost, 0) >= 50000 AND nvl(t2.investcost, 0) < 500000)
        then '2'
    when (t.customerintegral >= 0 AND t.customerintegral < 8188) OR (nvl(t2.investcost, 0) >= 0 AND nvl(t2.investcost, 0) < 50000)
        then '1'
    end) levelsign--, t.*, t2.*
--SELECT COUNT(*)    
FROM tcustintegral t, tcustcost t2
WHERE 1 = 1
AND t.customerid = t2.customerid(+)

縱觀本次錯誤經歷,再次驗證coding時要想不冒bug真得很難!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章