2017-09-18 121 views
3

我試圖將我的數據庫字段從VARCHAR(4)轉換爲FLOAT。這些字段中的某些值可能不是數字,因爲這些字段之前沒有任何驗證。我的主要目標是轉換浮點格式的任何integerdecimal值並保存在新的數據庫字段中。對於這個過程,我使用舊錶中的INSERT SELECT STATEMENT到新表中。到目前爲止,我有這行代碼爲我的轉換:如何將varchar(4)轉換爲在SQL Server 2008中浮動?

CASE WHEN LEN(LTRIM(RTRIM(hs_td2))) <> 0 AND ISNUMERIC(hs_td2) = 1 THEN CAST(LTRIM(RTRIM(hs_td2)) AS float) ELSE NULL END AS hs_td2 

第一步我修剪則值檢查它是否是數字,然後轉換爲浮動否則設置爲NULL。有了上面的代碼,我在微軟工作室收到此錯誤信息:

Msg 8114, Level 16, State 5, Line 13 
Error converting data type varchar to float. 

線13日開始我SELECT發言。然後我也嘗試了這種轉換:

CASE WHEN LEN(LTRIM(RTRIM(hs_td2))) <> 0 AND ISNUMERIC(hs_td2) = 1 THEN CONVERT(FLOAT, LTRIM(RTRIM(hs_td2))) ELSE NULL END AS hs_td2 

和我得到了同樣的錯誤信息。在我的字段中的值可能是這樣的:

10或5至10或0.9或11.6或-11.89等等...

我想知道如果isNumeric()是最好的功能,我應該使用和爲什麼我的代碼產生上面列出的錯誤信息?

如果有人可以幫忙,請讓我知道。謝謝!

+0

可能不是那些值。 'select cast(' - 11.89'as float)'執行成功。 –

+0

@DanBracuk我不知道是否NULL值可能會導致一些問題? –

+0

嘗試'hs_td2 NOT LIKE '%[^ 0-9]%' 或 ' - ' + hs_td2 NOT LIKE '%[^ 0-9]%''(反轉的條件,如果你第一次使用了'SELECT'希望看到無效值)。這仍然不能保證轉換會成功('1.1.1'通過這樣的方式滑動),但至少它過濾字母數字。 –

回答

2

不,ISNUMERIC不是最好的功能使用。

從本質上講,這個問題已經被問過,但不是在這個措辭:

Try_Convert for SQL Server 2008 R2

最upvoted答案建議轉換爲XML使用XML專用鑄件功能:

DECLARE @T TABLE (v varchar(4)); 

INSERT INTO @T (v) VALUES 
('1g23'), 
('-1.8'), 
('11.6'), 
('akjh'), 
('.'), 
('-'), 
('$'), 
('12,5'); 


select 
    cast('' as xml).value('sql:column("V") cast as xs:float ?', 'float') as new_v 
from @T 

我會在下面留下我的第一個答案。

很有可能你會得到轉換錯誤,因爲服務器試圖爲表的每一行運行CAST(LTRIM(RTRIM(hs_td2)) AS float),不僅僅是那些數字的。

當您嘗試使用WHERE ISNUMERIC(...) = 1過濾器過濾掉非數字行時,通常會發生這種情況。從技術上講,它也可能發生在CASE表達式中。

這就是爲什麼他們在2012年

我想嘗試編寫使用TRY-CATCH,並試圖爲給定值轉換成我自己的用戶自定義函數添加TRY_CONVERT。是的,它會很慢。


說了這麼多,下面CASE運行正常的例子:

DECLARE @T TABLE (v varchar(4)); 

INSERT INTO @T (v) VALUES 
('123'), 
('-1.8'), 
('11.6'), 
('akjh'), 
('123'); 

SELECT 
    CASE WHEN ISNUMERIC(v) = 1 THEN CAST(v AS float) ELSE NULL END AS new_v 
FROM @T; 

結果

+-------+ 
| new_v | 
+-------+ 
| 123 | 
| -1.8 | 
| 11.6 | 
| NULL | 
| 123 | 
+-------+ 

但是,如果我把一個.-$值,如所以:

INSERT INTO @T (v) VALUES 
('123'), 
('-1.8'), 
('11.6'), 
('akjh'), 
('$'); 

查詢失敗:

誤差變換數據類型爲varchar浮動。

可能還有其他特殊字符及其組合,ISNUMERIC不會抱怨。這就是我最初說整體而言,ISNUMERIC不是最好的功能。

如果這是一個一次性的轉換,你可以嘗試建立一個LIKE表情捕捉所有特殊情況是存在於你的數據,但如果你需要一個可靠的通用解決方案,升級到2012+和使用TRY_CONVERT或編寫你的T-SQL UDF或你的CLR UDF。

+0

那麼由於某種原因,我的發言是失敗的可能的複製...我在SQL Studio中看到很少的行,然後顯示錯誤消息。我不確定哪個值導致語句失敗。 –

+0

此代碼將失敗,如下所示:INSERT INTO @T(v)VALUES ('12,4') – sepupic

+0

@sepupic,是的,'ISNUMERIC'不是最好的函數,正如我從一開始就說的那樣。 –

0

這取決於值的VARCHAR列

ISNUMBER()用於vaule如''' - '將返回1,但是,它會失敗當你施放到FLOAT

ISNUMBER()的值,如'3D2','1E2' 將返回1,可CAST FLOAT,但是,你可能不希望將其視爲數字。

你可以試試下面的轉換

CASE WHEN 
    not LTRIM(RTRIM(hs_td2))like '%[^0-9.,-]%' -- Value only contains 0-9 . - 
    and LTRIM(RTRIM(hs_td2)) not like '.'   -- can not be only . 
    and LTRIM(RTRIM(hs_td2)) not like '-'   -- can not be only - 
    and isnumeric(LTRIM(RTRIM(hs_td2))) = 1 
THEN CAST(LTRIM(RTRIM(hs_td2)) AS float) 
ELSE NULL 
END 
+0

如何防止case語句中的非數字值?我也應該使用LTRIM(RTRIM(Value))? –

+0

使用上面提供的語句,每行的hs_td2列中的所有值均爲NULL。 –

+0

它似乎你有空間。您可能需要用LTRIM替換hs_td2(RTRIM(hs_td2)) – EricZ

1

SQLXML有足夠的力量使魔。當然,性能是問題。但仍然比百萬條件更好

DECLARE @T TABLE (v varchar(4)); 

INSERT INTO @T (v) VALUES 
('123'),('-1.8'),('11.6'),('akjh'),('$'),('-.'),('-.1'),(NULL); 

declare @Xml xml = (SELECT v FROM @T T for xml auto,elements); 

select T.v.value('v[1]','varchar(4)') v, T.v.value('max(v[1])','float') converted_v 
from @xml.nodes('/T') T(v); 
相關問題