2011-11-10 50 views
1

獲得一個誤差變換的varchar浮動。誤差變換VARCHAR浮動

有一個表(不是我製作)與result柱,有varchar數據。我想轉換爲浮動以獲取> 180.0的所有值。

SELECT result FROM table WHERE result > 180.0 

產生錯誤。有趣的是,雖然:

WITH temp AS (
    CASE 
    WHEN ISNUMERIC(result)=1 THEN CAST(result as FLOAT) 
    ELSE CAST(-1.0 AS FLOAT) 
    END AS result 
) 

這運行良好。當我與它配對:

SELECT temp.result FROM temp WHERE temp.result > 180.0 

我再次得到錯誤。思考?

UPDATE:請求完全的代碼...

WITH temp AS (
    SELECT 
    CASE 
    WHEN ISNUMERIC(result)=1 THEN CAST(result as FLOAT) 
    ELSE CAST(-1.0 AS FLOAT) 
    END AS result 
    FROM table) 

SELECT temp.result FROM temp WHERE temp.result > 180.0 

使用SQL-SERVER 2008 RC2。

+2

你能不能給您使用確切的語法?您的「WITH .. AS(CASE ...)」不完整且不正確。 –

+0

我試圖重現錯誤,但不能...我把以下代碼發佈和從@t中選擇並返回199. declare @t table(result varchar(500))insert into @t(result )值('199.00')插入到@t(結果)值('test'); –

+0

@Jeremy:你需要一個通過'ISNUMERIC'測試但不能轉換的測試值,比如'1,0''。 –

回答

9

這意味着你不能轉換爲float表至少有一個排。在做CASE是安全的,但相結合的CTE並增加一個WHERE子句編寫T-SQL時落入程序員的一個常見的謬誤:那秩序宣言意味着執行的順序。程序員習慣於像C語言這樣的命令式程序風格,而不能理解SQL的基於聲明式集合的特性。我對這個問題以前也寫了,給了例子,當謬誤導致錯誤:當您發佈完整的代碼,我們可以看到究竟你做的謬論

你的情況,並假定一定的執行順序。

後更新

OK,所以我必須要管理你的情況的代碼是在執行順序正確,result列不能投射W/O首先評估CASE。如果CASE在WHERE子句中,情況會有所不同。

你的問題是不同的:ISNUMERIC。這個函數有什麼NUMERIC手段非常慷慨的理解和之前已經被咬許多開發商。即,它接受CAST和CONVERT將拒絕的值。像包含逗號的那些:

declare @n varchar(8000) = '1,000'; 
select isnumeric(@n); 
select cast(@n as float); 
select case when isnumeric(@n)=1 then cast(@n as float) else null end; 

因此,您具有通過ISNUMERIC測試但未能轉換的值。只要站起來,你就會越深入這個方法,你會發現更多關閉的門。只是沒有安全的方法來做你需要在服務器端的演員。理想情況下,修復數據模型(如果該字段存儲浮點數,則使該字段爲浮點數)。除此之外,對數據進行分類並刪除所有不合適的浮點值,並修復前端/應用程序以不再引入新的值,然後添加一個約束條件,以便在出現新的錯誤值時觸發錯誤。在查詢中,你無法解決這個問題,這條路遍佈着屍體。

使用SQL Server的下一個版本,您將擁有一個可以解決您的問題的新功能TRY_CONVERT

+0

不幸的是,我不能改變數據庫的設計:(有沒有一個常見的習慣用於讓SQL Server吐出哪些行不能CAST/CONVERT? – chris

+1

不,不是真的,請參閱http://www.simple-talk .com/community/blogs/philfactor/archive/2011/01/13/98746.aspx –

+0

這種特殊情況下,IsNumeric已經分發,但像cast(result)這樣的記錄由於逗號而失敗,不幸的是很常見,您可以刪除逗號用REPLACE(result,',','')這樣的語句,如果可能的話儘量修正它, – Vic

3

檢查了這一點:

http://classicasp.aspfaq.com/general/what-is-wrong-with-isnumeric.html

基本上有與ISNUMERIC函數的一些已知問題/詭異。該文章的作者建議創建一個新函數並使用該函數替代ISNUMERIC。我用你建議的1,0值測試它,它似乎工作。


CREATE FUNCTION dbo.isReallyNumeric 
( 
    @num VARCHAR(64) 
) 
RETURNS BIT 
BEGIN 
    IF LEFT(@num, 1) = '-' 
     SET @num = SUBSTRING(@num, 2, LEN(@num)) 

    DECLARE @pos TINYINT 

    SET @pos = 1 + LEN(@num) - CHARINDEX('.', REVERSE(@num)) 

    RETURN CASE 
    WHEN PATINDEX('%[^0-9.-]%', @num) = 0 
     AND @num NOT IN ('.', '-', '+', '^') 
     AND LEN(@num)>0 
     AND @num NOT LIKE '%-%' 
     AND 
     ( 
      ((@pos = LEN(@num)+1) 
      OR @pos = CHARINDEX('.', @num)) 
     ) 
    THEN 
     1 
    ELSE 
    0 
    END 
END 
GO 
+0

這很好用,它找到了一個負數來阻止float float – prospector

1

只是一個顯式轉換但有一點巧思替換

SELECT result FROM table WHERE CONVERT(float,REPLACE(result,',','.')) > 180.0 
相關問題