Format value to configured number of decimal places
-
06-10-2020 - |
题
I want to format a number to display decimal places according to a configuration value specified in another table. If the configured value is NULL, the number of decimal places should default to 2 (hardcoded here) The following statement works fine except that for values like 3.50000 which returns 3.5 even when the configured value for 'NumberOfDecimalPlaces' is 2 or 3. I get that it is the desired behavior for ROUND()
ROUND([ActualValue], COALESCE([ConfigurationTable].[NumberOfDecimalPlaces], 2)) [FormattedActualValue]
As an alternative, I tried CONVERT AND CAST.
SELECT CAST ([ActualValue] AS NUMERIC(16, COALESCE([ConfigurationTable].[NumberOfDecimalPlaces], 2))
SELECT CONVERT(DECIMAL (16, COALESCE([ConfigurationTable].[NumberOfDecimalPlaces], 2)), [ActualValue])
Both of which err to Incorrect syntax near the keyword 'COALESCE'.
I understand that the second parameter to the datatype definition is not nullable and hence the error. What are my options? How can I achieve this with minimum performance overhead?
解决方案
The STR function seems to be what you're looking for:
DECLARE @NumberOfDecimalPlaces tinyint = 3;
DECLARE @ActualValue decimal(16,5) = 3.50
SELECT FormattedActualValue =
STR(
@ActualValue,
CAST(@ActualValue / 10 AS int) + @NumberOfDecimalPlaces + 2,
COALESCE(@NumberOfDecimalPlaces,2)
)
其他提示
You can't use parameters/variables for precision, so you'll need to use dynamic SQL for this. Performance overhead here is relatively close to zero.
DECLARE @NumberOfDecimalPlaces tinyint;
SET @NumberOfDecimalPlaces = 3;
DECLARE @sql nvarchar(max) = N'SELECT FormattedActualValue =
CONVERT(DECIMAL(16, $decimal_places$), 13.5457);';
SET @sql = REPLACE(@sql, N'$decimal_places$', COALESCE(@NumberOfDecimalPlaces,2));
EXEC sys.sp_executesql @sql;
After seeing Gianluca's answer I started to play with something else, which may or may not suit your needs (depending on whether you want trailing zeros when @DecimalPlaces > (decimal places in original value)
:
DECLARE @DecimalPlaces tinyint = 5,
@ActualValue decimal(16,5) = 3.561735;
SELECT LTRIM(STR(ROUND(@ActualValue,@DecimalPlaces),20,@DecimalPlaces));
The FORMAT function accepts a wide variety of input types. The output can be formatted to the culture & locale of the user. It produces an nvarchar result.
This is a slight alteration to spaghettidba's answer. When specifying the number of digits to show, you need to do something other than devide the value by 10:
The STR function accepts 3 arguments:
STR( [Value],[Total Number of Didgits],[Decimal Places])
The correct calculation of [Total Number of Didgits] should be something like:
LEN(CAST(ROUND([Value], 0) AS INT)) + [Decimal Places] + 1
/* + 1 for the decimal point itself */
this will get the number of digits before the decimal place. E.g.
DECLARE @NumberOfDecimalPlaces TINYINT = 3;
DECLARE @ActualValue DECIMAL(16, 5) = .005643
SELECT FormattedActualValue = STR(@ActualValue, LEN(CAST(ROUND(@ActualValue, 0) AS INT)) + @NumberOfDecimalPlaces + 1, @NumberOfDecimalPlaces)