如何将SQL子字符串转换为十进制?

时间:2013-07-29 17:21:53

标签: sql sql-server sql-server-2008

我在表PriceTerm中有一个varchar列,其中包含各种字符串。所以我想将其中一些复制到另一列。

所以源名称和格式是

[AdditionalDescription] [varchar](255) NOT NULL

和目的地

[PercentAddition] [decimal](28, 10) NOT NULL

我只想转换那些包含SQL挑选的%:

select AdditionalDescription from PriceTerm where AdditionalDescription like '%[%]%'

输出是这样的。

AdditionalDescription
7,5 %
7,5%
7,5%
6 %
7,5%
6 %
3 %
....

返回1696475行,所以很多。

显然我必须删除%符号才能将其转换为十进制值。

所以我认为这是几个子步骤。

  1. 选择要转换的行。由上面的SQL完成。
  2. 删除%,只留下字符串中的数字。
  3. 将字符串转换为十进制并将其放在PercentAddition列中。
  4. 我的问题是如何实施第2步和第3步?

    更新 我试过那两个SQL。

    SELECT 
    CONVERT(decimal(28,10), LTRIM(RTRIM(REPLACE(REPLACE([ADDITIONALDESCRIPTION], ',', '.'), '%', ''))))
    FROM PriceTerm
    WHERE AdditionalDescription like '%[%]%'
    
    SELECT 
    CAST(LTRIM(RTrim(REPLACE(REPLACE([ADDITIONALDESCRIPTION], ',', '.'), '%', ''))) AS Decimal(28,10))
    FROM PriceTerm
    WHERE AdditionalDescription like '%[%]%'
    

    两者都返回了相同的错误。

    将数据类型varchar转换为数字时出错。

    但以下作品

    选择 CONVERT(十进制(28,10),LTRIM(RTRIM(REPLACE('5,8%',',','。'),'%',''))))) 来自PriceTerm 其他描述如'%[%]%'

    我尝试列出那些符合条件并且转换失败的人。

    选择 LTRIM(RTRIM(REPLACE(REPLACEALDESCRIPTION),',','。'),'%','')))作为PercentAddition 来自PriceTerm WHERE(AdditionalDescription,如'%[%]%')和ISNUMERIC(LTRIM(RTRIM(REPLACE([ADDITIONALDESCRIPTION],',','。'),'%',''))))= 0

    PercentAddition
    express + 30
    Express Transport +30
    tillägg till faktura 115423. express +30
    + 30    (1.30*42.4sek=55.12sek)
    + 30    (1.30*42.4sek=55.12sek)
    7.5*
    7.5*
    7..5
    7..5
    7.5.
    7.5.
    1.5  (minimi 4.20 €)
    335 * 25 = 418.75
    335 * 25= 418.75
    10.6 &
    vastaanottajan rahdinmaksu +4
    Expressfrakt!!+30
    

    奇怪的是,这些都不包含%char。

    更新2: 我尝试过滤掉无法使用此SQL转换的数据

    SELECT AdditionalDescription
    FROM PriceTerm 
    WHERE Created BETWEEN '2004' AND '2005' AND
    AdditionalDescription like '%[%]%' AND
    PercentAddition = 0 AND 
    ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 0
    

    输出:

    AdditionalDescription
    
    Snabbleverans + 30 %
    Snabbleverans + 30 %
    455 € + 4%
    1,5 % (minimi 4,20 €)
    1,5 % (minimi 4,20 €)
    bränsle 7,5% ingår.
    

    所以这些字符串包含%但不能将它们转换为小数。我想跳过那些。

    计算有效数字

    SELECT Count(*)
    FROM PriceTerm 
    WHERE Created BETWEEN '2004' AND '2005' AND
    AdditionalDescription like '%[%]%' AND
    PercentAddition = 0 AND 
    ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 1
    

    80051

    更新PercentAddition列

    UPDATE PriceTerm 
    SET PercentAddition = CONVERT(decimal(28,10), RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.'))))
    WHERE Created BETWEEN '2004' AND '2005' AND
    AdditionalDescription LIKE '%[%]%' AND
    PercentAddition = 0
    AND ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 1
    

    结果

    将数据类型varchar转换为数字时出错。

    任何有暗示原因的人?

    更新3:

    因此,例如,无法解析上面所有那些奇怪的行是gonne被滑倒。

    + 30    (1.30*42.4sek=55.12sek)
    7.5*
    7.5*
    7..5
    

    以上所有内容都将转换为0.只有那些将转换为十进制:

    7,5%  -> 7.5
    7,7 % -> 7.7
    2.5   -> 2.5
    

    我还试图找出SQL CASE WHEN的工作原理。可能有用吗? 试过这个:

    UPDATE PriceTerm 
    SET PercentAddition = 
      CASE
        WHEN ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 1 THEN      
          CONVERT(decimal(28,10), RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.'))))
        ELSE 
          0.0
        END 
    WHERE Created BETWEEN '2004' AND '2005' AND
    AdditionalDescription LIKE '%[%]%' AND
    PercentAddition = 0
    AND ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 1
    

    输出仍然将数据类型varchar转换为数字时出错。 我甚至考虑过一个存储过程,但我之前从未使用过它。 SQL Server 2012具有Try_Convert,在这种情况下非常有用。但我没有找到类似2008 R2的替代品。

3 个答案:

答案 0 :(得分:2)

不要考虑效率如何:

Select convert(decimal(28,10), rtrim(ltrim(replace(REPLACE(AdditionalDescription,'%',''), ',','.')))) As AdditionalDescription
from PriceTerm 
where AdditionalDescription like '%[%]%'

说明:

  1. 通过替换空格
  2. 删除%
  3. ,替换为.
  4. 删除任何前导或尾随空格。
  5. 转换为decimal(28, 10)
  6. 更新

    根据OP的附加信息。

    Select 
    convert(decimal(28,10),replace(replace(replace(rtrim(ltrim(AdditionalDescription)), ' ',''),',','.'),'%','')) AS PercentAddition
    from test 
    where replace(rtrim(ltrim(AdditionalDescription)), ' ','')
    like '[0-9]%[,.]%[%0-9]'
    and 
    isnumeric(replace(replace(replace(rtrim(ltrim(AdditionalDescription)), ' ',''),',','.'),'%',''))=1
    

    '[0-9]%[,.]%[%0-9]'的解释:

    • [0-9] - 我们只对数据以数字开头时感兴趣。
    • % - 数字后可能包含任何字符。我们在isnumeric子句中使用where来处理非数字。
    • [,.] - 我们的数据包含,.
    • % - 在[,.]之后,它可能包含任何字符。我们在isnumeric子句中使用where来处理非数字。
    • [%0-9] - 我们希望数据以数字或%结尾。

    注意:当您发现更多不良字符时,您必须修改'[0-9]%[,.]%[%0-9]'

    <强>参考文献:

    1. 使用SQLFiddle:http://sqlfiddle.com/#!3/09a34/4
    2. LIKE - http://msdn.microsoft.com/en-us/library/ms179859(v=sql.90).aspx

答案 1 :(得分:1)

这不是最快的方法,但试试这个:

SELECT CONVERT(DECIMAL(5, 2), REPLACE(REPLACE(AdditionalDescription, '%', ''), ',', '.')) AS DecimalValue
FROM   PriceTerm
WHERE  AdditionalDescription LIKE '%[%]%'

这将用空字符串替换%和带点的逗号,因此7,5%将看起来像7.5然后转换为小数。

答案 2 :(得分:1)

事实证明,如果字符串是数字,最难的部分是验证。内置程序IsNumeric返回误报。即使结果为1,CONVERT也无法将字符串转换为Decimal。谷歌和site

提供了救援

我使用存储过程。

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 

并像这样使用它:

UPDATE PriceTerm 
SET PercentAddition = CONVERT(decimal(28,10), RTRIM(LTRIM(REPLACE(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.'), '&', '')))) 
WHERE AdditionalDescription LIKE '%[%]%' AND
dbo.isreallynumeric(RTRIM(LTRIM(REPLACE(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.'), '&', '')))) = 1 AND
PercentAddition = 0