VARCHAR to DECIMAL

前端 未结 12 622
清歌不尽
清歌不尽 2020-12-06 09:24

I want to convert a varchar(max) column to decimal(10,4).

When I try to use cast or convert I am getting an arit

相关标签:
12条回答
  • 2020-12-06 09:46

    My explanation is in the code. :)

    DECLARE @TestConvert VARCHAR(MAX) = '123456789.1234567'
    BEGIN TRY
        SELECT CAST(@TestConvert AS DECIMAL(10, 4))
    END TRY
    BEGIN CATCH
        SELECT 'The reason you get the message "' + ERROR_MESSAGE() + '" is because DECIMAL(10, 4) only allows for 4 numbers after the decimal.'
    END CATCH
    
    -- Here's one way to truncate the string to a castable value.
    SELECT CAST(LEFT(@TestConvert, (CHARINDEX('.', @TestConvert, 1) + 4)) AS DECIMAL(14, 4))
    
    -- If you noticed, I changed it to DECIMAL(14, 4) instead of DECIMAL(10, 4) That's because this number has 14 digits, as proven below.
    -- Read this for a better explanation as to what precision, scale and length mean: http://msdn.microsoft.com/en-us/library/ms190476(v=sql.105).aspx
    SELECT LEN(LEFT(@TestConvert, (CHARINDEX('.', @TestConvert, 1) + 4)))
    
    0 讨论(0)
  • 2020-12-06 09:46

    In case you need to ROUND the result, not truncate, can use this:

    select convert(decimal(38,4), round(convert(decimal(38,10), '123456789.1234567'),4))
    

    This will return the following:

    '123456789.1235' for '123456789.1234567'
    '123456789.1234' for '123456789.1234467'
    
    0 讨论(0)
  • 2020-12-06 09:47

    You are missing the fact that 6.999,50 is not a valid decimal. You can't have a comma and a decimal point in a decimal value surely? What number is it supposed to be?

    Assuming your locale specifies . as grouping and , as decimal separator: To remove the grouping digits:

    SELECT CONVERT(decimal(11,2), REPLACE('6.999,50', '.', ''))

    will yield 6999,50 as a decimal

    0 讨论(0)
  • 2020-12-06 09:53
    create function [Sistema].[fParseDecimal]
    (
        @Valor nvarchar(4000)
    )
    returns decimal(18, 4) as begin
        declare @Valores table (Valor varchar(50));
    
        insert into @Valores values (@Valor);
    
        declare @Resultado decimal(18, 4) = (select top 1 
            cast('' as xml).value('sql:column("Valor") cast as xs:decimal ?', 'decimal(18, 4)')
        from @Valores);
        
        return @Resultado;
    END
    
    0 讨论(0)
  • 2020-12-06 09:58

    In MySQL

    select convert( if( listPrice REGEXP '^[0-9]+$', listPrice, '0' ), DECIMAL(15, 3) ) from MyProduct WHERE 1
    
    0 讨论(0)
  • 2020-12-06 09:59

    I came up with the following solution:

    SELECT [Str], DecimalParsed = CASE 
    WHEN ISNUMERIC([Str]) = 1 AND CHARINDEX('.', [Str])=0 AND LEN(REPLACE(REPLACE([Str], '-', ''), '+', '')) < 29 THEN CONVERT(decimal(38,10), [Str])
    WHEN ISNUMERIC([Str]) = 1 AND (CHARINDEX('.', [Str])!=0 AND CHARINDEX('.', REPLACE(REPLACE([Str], '-', ''), '+', ''))<=29) THEN 
        CONVERT(decimal(38,10), 
                CASE WHEN LEN([Str]) - LEN(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE([Str], '0', ''), '1', ''), '2', ''), '3', ''), '4', ''), '5', ''), '6', ''), '7', ''), '8', ''), '9', '')) <= 38 
                     THEN [Str] 
                     ELSE SUBSTRING([Str], 1, 38 + LEN(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE([Str], '0', ''), '1', ''), '2', ''), '3', ''), '4', ''), '5', ''), '6', ''), '7', ''), '8', ''), '9', ''))) END)
    ELSE NULL END
    FROM TestStrToDecimal
    

    I know it looks like an overkill and probably it is, but it works for me (checked both positive, negative, big and small numbers of different precision and scale - everything is converted to decimal(38,10) or NULL).

    It is hard-coded to decimal(38,10) type, so if you need different precision, change the constants in the code (38, 10, 29).

    How it works? The result is:

    • if conversion is simple without overflow or precision loss (e.g. 123 or 123.456), then it just convert it.
    • if number is not too big, but has too many digits after decimal point (e.g. 123.1234567890123456789012345678901234567890), then it trims the exceeding digits at the end keeping only 38 first digits.
    • if number is too big and can't be converted to decimal without an overflow (e.g. 9876543210987654321098765432109876543210), then NULL is returned

    each case is separate WHEN statement inthe code above.

    Here are few examples of conversion: enter image description here

    0 讨论(0)
提交回复
热议问题