2013-11-21 17 views
1

我有一個應該有浮動值(價格)的數據字段,但是,數據庫設計師已經搞砸了,現在我必須在該字段上執行聚合函數。而80%的時間數據格式正確,例如。 '80.50',有時節省爲$ 80.50或$ 80.50每平方米。從字符串/文本提取浮動SQL Server

數據字段是nvarchar。我需要做的是從nvarchar中提取浮點數。我來到這裏:Article on SQL Authority

然而,這,解決了我的問題的一半,或者複合它,有些人可能會說。該函數只是返回字符串中的數字。那就是「每平方米80.50美元」將返回80502.顯然,這不會起作用。我嘗試將=> PATINDEX('%[^ 0-9]%',@strAlphaNumeric)的正則表達式更改爲=> PATINDEX('%[^ 0-9]。[^ 0-9]%', @strAlphaNumeric) 不起作用。任何幫助,將不勝感激。

+0

你對「每平方米$ 80.50」的回答是什麼? – Dhaval

回答

2

這也應該工作,但它假定float數字後面跟着一個空格,以防文本之後有文本。

// sample data 
DECLARE @tab TABLE (strAlphaNumeric NVARCHAR(30)) 
INSERT @tab VALUES ('80.50'),('$80.50'),('$80.50 per sqm') 

// actual query 
SELECT 
    strAlphaNumeric AS Original, 
    CAST (
    SUBSTRING(stralphanumeric, PATINDEX('%[0-9]%', strAlphaNumeric), 
     CASE WHEN PATINDEX('%[ ]%', strAlphaNumeric) = 0 
     THEN LEN(stralphanumeric) 
     ELSE 
     PATINDEX('%[ ]%', strAlphaNumeric) - PATINDEX('%[0-9]%', strAlphaNumeric) 
     END 
    ) 
    AS FLOAT) AS CastToFloat 
FROM @tab 

從上面的樣本數據,生成:

Original      CastToFloat 
------------------------------ ---------------------- 
80.50       80,5 
$80.50       80,5 
$80.50 per sqm     80,5 

樣品SQL Fiddle

如果你想要的東西更強大的,你可能要考慮編寫一個CLR函數來做,而不是像MSDN文章中所描述的正則表達式解析:Regular Expressions Make Pattern Matching And Data Extraction Easier

2

這將千方百計想讓你所需要的,在(http://sqlfiddle.com/#!6/6ef8e/53

測試
DECLARE @data varchar(max) = '$70.23 per m2' 
Select LEFT(SubString(@data, PatIndex('%[0-9.-]%', @data), 
        len(@data) - PatIndex('%[0-9.-]%', @data) +1 
       ), 
     PatIndex('%[^0-9.-]%', SubString(@data, PatIndex('%[0-9.-]%', @data), 
        len(@data) - PatIndex('%[0-9.-]%', @data) +1)) 
     ) 

但作爲JPW已經提到正則表達式在CLR會更好

+0

這會錯過像'80.50'和'$ 80.50'這樣的值並返回空格。 – jpw

+0

我測試了它的值,但是找不到一個除123以外的值。55但是RegEx也會失敗這個值 – deterministicFail

0

啓發上@deterministicFail,我想到了一個辦法,只提取數字部分(雖然我噸的不是100%):

DECLARE @NUMBERS TABLE (
    Val VARCHAR(20) 
) 
INSERT INTO @NUMBERS VALUES 
('$70.23 per m2'), 
('$81.23'), 
('181.93 per m2'), 
('1211.21'), 
(' There are 4 tokens'), 
(' No numbers '), 
(''), 
(' ') 
select 
    CASE 
     WHEN ISNUMERIC(RTRIM(LEFT(RIGHT(RTRIM(LTRIM(n.Val)), 1+LEN(RTRIM(LTRIM(n.Val)))-PatIndex('%[0-9.-]%', RTRIM(LTRIM(n.Val)))), LEN(RIGHT(RTRIM(LTRIM(n.Val)), 1+LEN(RTRIM(LTRIM(n.Val)))-PatIndex('%[0-9.-]%', RTRIM(LTRIM(n.Val)))))- PATINDEX('%[^0-9.-]%',RIGHT(RTRIM(LTRIM(n.Val)), 1+LEN(RTRIM(LTRIM(n.Val)))-PatIndex('%[0-9.-]%', RTRIM(LTRIM(n.Val))))))))=1 THEN 
      RTRIM(LEFT(RIGHT(RTRIM(LTRIM(n.Val)), 1+LEN(RTRIM(LTRIM(n.Val)))-PatIndex('%[0-9.-]%', RTRIM(LTRIM(n.Val)))), LEN(RIGHT(RTRIM(LTRIM(n.Val)), 1+LEN(RTRIM(LTRIM(n.Val)))-PatIndex('%[0-9.-]%', RTRIM(LTRIM(n.Val)))))- PATINDEX('%[^0-9.-]%',RIGHT(RTRIM(LTRIM(n.Val)), 1+LEN(RTRIM(LTRIM(n.Val)))-PatIndex('%[0-9.-]%', RTRIM(LTRIM(n.Val))))))) 
     ELSE '0.0' 
    END 
FROM @NUMBERS n 
+0

產生很好的輸出,但是親愛的上帝會變得混亂。 46 x'左/右/ LTRIM/RTRIM' – OGHaza

+0

@OGHaza,我同意。根據輸入的字符串,你可以刪除ltrim和rtrim。我在插入空白字符串''作爲測試用例時使用了這些函數。 – Erick

+0

好點。如果存在領先的空白,jpw的答案會落空 - 儘管他當然也可以修剪輸入。 – OGHaza