How do I format a number with commas in T-SQL?

2019-01-04 08:10发布

I'm running some administrative queries and compiling results from sp_spaceused in SQL Server 2008 to look at data/index space ratios of some tables in my database. Of course I am getting all sorts of large numbers in the results and my eyes are starting to gloss over. It would be really convenient if I could format all those numbers with commas (987654321 becomes 987,654,321). Funny that in all the many years I've used SQL Server, this issue has never come up since most of the time I would be doing formatting at the presentation layer, but in this case the T-SQL result in SSMS is the presentation.

I've considered just creating a simple CLR UDF to solve this, but it seems like this should be do-able in just plain old T-SQL. So, I'll pose the question here - how do you do numeric formatting in vanilla T-SQL?

14条回答
干净又极端
2楼-- · 2019-01-04 08:46

Here is a scalar function I am using that fixes some bugs in a previous example (above) and also handles decimal values (to the specified # of digits) (EDITED to also work with 0 & negative numbers). One other note, the cast as money method above is limited to the size of the MONEY data type, and doesn't work with 4 (or more) digits decimals. That method is definitely simpler but less flexible.

CREATE FUNCTION [dbo].[fnNumericWithCommas](@num decimal(38, 18), @decimals int = 4) RETURNS varchar(44) AS
BEGIN
    DECLARE @ret varchar(44)

    DECLARE @negative bit; SET @negative = CASE WHEN @num < 0 THEN 1 ELSE 0 END

    SET @num = abs(round(@num, @decimals)) -- round the value to the number of decimals desired
    DECLARE @decValue varchar(18); SET @decValue = substring(ltrim(@num - round(@num, 0, 1)) + '000000000000000000', 3, @decimals)
    SET @num = round(@num, 0, 1) -- truncate the incoming number of any decimals
    WHILE @num > 0 BEGIN
        SET @ret = str(@num % 1000, 3, 0) + isnull(','+@ret, '')
        SET @num = round(@num / 1000, 0, 1)
    END
    SET @ret = isnull(replace(ltrim(@ret), ' ', '0'), '0') + '.' + @decValue
    IF (@negative = 1) SET @ret = '-' + @ret

    RETURN @ret
END

GO
查看更多
SAY GOODBYE
3楼-- · 2019-01-04 08:47

Demo 1

Demonstrates adding commas:

PRINT FORMATMESSAGE('The number is: %s', format(5000000, '#,##0'))
-- Output
The number is: 5,000,000

Demo 2

Demonstrates commas and decimal points. Observe that it rounds the last digit if necessary.

PRINT FORMATMESSAGE('The number is: %s', format(5000000.759145678, '#,##0.00'))
-- Output
The number is: 5,000,000.76

Compatibility

SQL Server 2012+.

查看更多
够拽才男人
4楼-- · 2019-01-04 08:49

I'd recommend Replace in lieu of Substring to avoid string length issues:

REPLACE(CONVERT(varchar(20), (CAST(SUM(table.value) AS money)), 1), '.00', '')
查看更多
【Aperson】
5楼-- · 2019-01-04 08:50

Another UDF which is hopefully generic enough and does not make assumptions about whether you want to round to a specific number of decimal places:

CREATE FUNCTION [dbo].[fn_FormatNumber] (@number decimal(38,18))

RETURNS varchar(50)

BEGIN
    -- remove minus sign before applying thousands seperator
    DECLARE @negative bit
    SET @negative = CASE WHEN @number < 0 THEN 1 ELSE 0 END
    SET @number = ABS(@number)

    -- add thousands seperator for every 3 digits to the left of the decimal place
    DECLARE @pos int, @result varchar(50) = CAST(@number AS varchar(50))
    SELECT @pos = CHARINDEX('.', @result)
    WHILE @pos > 4
    BEGIN
        SET @result = STUFF(@result, @pos-3, 0, ',')
        SELECT @pos = CHARINDEX(',', @result)
    END

    -- remove trailing zeros
    WHILE RIGHT(@result, 1) = '0'
        SET @result = LEFT(@result, LEN(@result)-1)
    -- remove decimal place if not required
    IF RIGHT(@result, 1) = '.'
        SET @result = LEFT(@result, LEN(@result)-1)

    IF @negative = 1
        SET @result = '-' + @result

    RETURN @result
END
查看更多
等我变得足够好
6楼-- · 2019-01-04 08:52

Tried the money trick above, and this works great for numerical values with two or less significant digits. I created my own function to format numbers with decimals:

CREATE FUNCTION [dbo].[fn_FormatWithCommas] 
(
    -- Add the parameters for the function here
    @value varchar(50)
)
RETURNS varchar(50)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @WholeNumber varchar(50) = NULL, @Decimal varchar(10) = '', @CharIndex int = charindex('.', @value)

    IF (@CharIndex > 0)
        SELECT @WholeNumber = SUBSTRING(@value, 1, @CharIndex-1), @Decimal = SUBSTRING(@value, @CharIndex, LEN(@value))
    ELSE
        SET @WholeNumber = @value

    IF(LEN(@WholeNumber) > 3)
        SET @WholeNumber = dbo.fn_FormatWithCommas(SUBSTRING(@WholeNumber, 1, LEN(@WholeNumber)-3)) + ',' + RIGHT(@WholeNumber, 3)



    -- Return the result of the function
    RETURN @WholeNumber + @Decimal

END
查看更多
走好不送
7楼-- · 2019-01-04 08:52
`/* Author: Tsiridis Dimitris */
/* Greek amount format. For the other change the change on replace of '.' & ',' */
CREATE FUNCTION dbo.formatAmount  (
@amtIn as varchar(20)
) RETURNS varchar(20)
AS
BEGIN 

return cast(REPLACE(SUBSTRING(CONVERT(varchar(20), CAST(@amtIn AS money), 1),1,
LEN(CONVERT(varchar(20), CAST(@amtIn AS money), 1))-3), ',','.')
 + replace(RIGHT(CONVERT(varchar(20), CAST(@amtIn AS money), 1),3), '.',',') AS VARCHAR(20))

END

SELECT [geniki].[dbo].[formatAmount]('9888777666555.44')`
查看更多
登录 后发表回答