从String / Text SQL Server中提取float

时间:2013-11-21 09:18:29

标签: sql sql-server regex

我有一个应该具有浮动值(价格)的数据字段,但是,数据库设计者搞砸了,现在我必须在该字段上执行聚合函数。而80%的时间数据格式正确,例如。 '80 .50',有时保存为'$ 80.50'或'$ 80.50每平方米'。

数据字段是nvarchar。我需要做的是从nvarchar中提取浮点数。我来到这里:Article on SQL Authority

然而,有些人可能会说,这可以解决我的一半问题或复合问题。该函数只返回字符串中的数字。这是'每平方米80.50美元'将返回80502.显然不会工作。我试图从=>更改正则表达式     PATINDEX('%[^ 0-9]%',@ ssAlphaNumeric)to =>     PATINDEX('%[^ 0-9]。[^ 0-9]%',@ ssAlphaNumeric) 不起作用。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

这也应该有效,但它假设浮点数后跟一个空格,以防后面有文字。

// 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

答案 1 :(得分: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上的正则表达式会更好

答案 2 :(得分: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