2014-01-27 45 views
0

我在處理審計日誌,並且希望忽略NULL值更改爲零(或保持爲NULL)的條目。無論正在記錄的字段的類型如何,舊值和新值都保存在NVARCHAR字段中。爲了CAST一個新值到十進制,以確定它是否爲零,我需要限制的情況下,字段的ISNUMERIC返回1.克服SQL缺少AND條件的短路

我已經得到它與這個奇怪的SQL的工作 - 但感覺肯定有一個更好的辦法。

WHERE MessageDesc LIKE 'poitem%' 
AND NOT(OldValue IS NULL AND 0.0 = 
    CASE 
     WHEN ISNUMERIC(NewValue) = 1 THEN CAST(NewValue AS DECIMAL(18,4)) 
     WHEN NewValue IS NULL THEN 0.0 
     ELSE 1.0 
    END) 

有什麼建議嗎?

回答

0

避免ISNUMERIC(),因爲它與'。'有關。

-- Dot comes up as valid numeric 
select 
    ISNUMERIC('.') as test1, 
    ISNUMERIC('1A') as test2, 
    ISNUMERIC('1') as test3, 
    ISNUMERIC('A1') as test4 

-- Results window (text) 
test1  test2  test3  test4 
----------- ----------- ----------- ----------- 
1   0   1   0 

改爲使用COALESCE()。

WHERE MessageDesc LIKE 'poitem%' 
AND 
    NOT (OldValue IS NULL AND 
    CAST(COALESCE(NewValue, '0') AS DECIMAL(18,4)) = 0) 
+0

這似乎並不工作,當NewValue是會產生一個「錯誤轉換數據類型varchar數值」。 - 儘管你說得對,那是單一的「。」導致我的代碼也出錯。 – JakeA

1

SQL Server 2012添加了一個Try_Convert函數,如果該值無法作爲給定類型轉換,則返回NULL。 http://technet.microsoft.com/en-us/library/hh230993.aspx

WHERE NOT (OldValue is Null AND 
    (NewValue is null OR try_convert(float, NewValue) = 0.0) 
) 

如果使用之前的2012年的版本,看看這裏Damien_The_Unbeliever的回答是: Check if a varchar is a number (TSQL) ...根據阿龍的評論,這將不會適用於所有情況。

由於您使用的是SQL 2008,因此它看起來是一個組合的isnumeric,並且來自上面鏈接的Damien答案的修改版本可以工作。您的問題中的當前解決方案會遇到諸如'。',' - ',貨幣符號($等)以及科學記數法(如'1e4')的問題。

試試SQL 2008(這裏是SQLFiddle與測試用例:http://sqlfiddle.com/#!3/fc838/3):注意:如果文本有逗號(例如:1,000)或會計符號與parens(例如:使用此解決方案不會將文本值轉換爲數字「(1)」表示「-1」),因爲SQL Server在嘗試轉換爲十進制時會引發錯誤。

WHERE t.OldValue is null 
AND 
(
    t.NewValue is null 
    OR 
    0.0 = 
    case 
     when isnumeric(t.NewValue) = 1 
      --Contains only characters that are numeric, negative sign, or decimal place. 
      --This is b/c isnumeric will return true for currency symbols, scientific notation, or '.' 
      and not (t.NewValue like '%[^0-9.\-\+]%' escape '\') 
      --Not other single char values where isnumeric returns true. 
      and t.NewValue not in ('.', '-', '+') 
     then cast(t.NewValue as decimal(18,4)) 
     else null --can't convert to a decimal type 
    end 
) 
+0

對不起 - 我應該說我們在2008年... – JakeA