2012-11-20 61 views
1

使用Teradata數據庫,可以通過Java將NaN,-Inf和+ Inf的值加載到FLOAT列中。不幸的是,一旦這些值進入表格,編寫需要將它們過濾掉的SQL就會讓生活變得困難。沒有IsNaN()函數,也不能「CAST('NaN'作爲FLOAT)」並使用相等比較。如何過濾Teradata SQL中的NaN FLOAT值?

我想要做的是,

SELECT 
    SUM(VAL**2) 
FROM 
    DTM 
WHERE 
    NOT ABS(VAL) > 1e+21 AND 
    NOT VAL = CAST ('NaN' AS FLOAT) 

但失敗,錯誤2620,「格式或數據包含不良性格。」,專門對CAST。我試過簡單的「... AND NOT VAL ='NaN'」,這也因爲類似的原因而失敗(3535,「字符串未能轉換爲數字值。」)。我似乎無法弄清楚如何在SQL語句中表示NaN。即使我可以在SQL語句中成功表示NaN,我也會擔心比較會失敗。根據IEEE 754規範,NaN = NaN應評估爲false。我真的需要的是一個IsNaN()函數。然而,這個功能似乎並不存在。

回答

0

我已經想出了一個解決方法,我將與那些尋找解決方案的人分享。但首先,Teradata對NaN浮點值的處理是不完整的,而且我偶然發現的任何行爲都可能是無意的,並且在不同版本之間不一致。因此,我提供以下免費建議,不提供任何擔保,承諾或任何形式的責任。買者自負。

在深入研究數據後,我發現如果將FLOAT值CASTT值設置爲VARCHAR(50),則NaN值會以22個星號(**********************)的字符串形式出現。我可以將其轉換爲VARCHAR(1),並將NaN作爲單個星號出現(*)。這種比較並不壞。

SELECT 
    SUM(VAL**2) 
FROM 
    DTM 
WHERE 
    NOT CAST (VAL AS VARCHAR(1)) = '*' AND 
    ABS(VAL) < 1.0e+21 

我會注意到兩件事。首先,我對Teradata版本的「NOT ABS(VAL)> 1.0e + 21」的原始願望似乎轉化爲「ABS(VAL)< = 1.0e + 21」。這個(有時)由於比較的等式部分而失敗 - 錯誤[2651],「涉及VAL的操作錯誤計算表達式」。我假設從「NOT>」到「< =」的轉換正在發生,因爲「NOT ABS(VAL)> = 1.0e + 21」正常工作(但看起來很難看)。使用「ABS(VAL)< 1.0e + 21」可以很好地工作並捕捉需求。其次,雖然我不能一致地重現它,但在我的歷史記錄中,「ABS(VAL)< = 1.0e + 21」確實有效地篩選出NaN,有些地方沒有NaN,有些地方它失敗[2651](見上文),但表中的SQL和數據是相同的。我可以得出的唯一結論是Teradata在NaN參與(或認爲可能)時如何評估比較結果不一致。不同的放大器可能會以不同的方式處理,但我不確定。也就是說,where子句中的上述兩個比較始終如一地有效地篩選Inf和NaN值。