2013-11-21 19 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