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
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)))
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'
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
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
In MySQL
select convert( if( listPrice REGEXP '^[0-9]+$', listPrice, '0' ), DECIMAL(15, 3) ) from MyProduct WHERE 1
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:
each case is separate WHEN statement inthe code above.
Here are few examples of conversion: