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

Sql ServerTsql

Sql Server Problem Overview


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?

Sql Server Solutions


Solution 1 - Sql Server

In SQL Server 2012 and higher, this will format a number with commas:

select format([Number], 'N0')

You can also change 0 to the number of decimal places you want.

Solution 2 - Sql Server

While I agree with everyone, including the OP, who says that formatting should be done in the presentation layer, this formatting can be accomplished in T-SQL by casting to money and then converting to varchar. This does include trailing decimals, though, that could be looped off with SUBSTRING.

SELECT CONVERT(varchar, CAST(987654321 AS money), 1)

Solution 3 - Sql Server

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', '')

Solution 4 - Sql Server

For SQL Server 2012+ implementations, you will have the ability to use the FORMAT to apply string formatting to non-string data types.

In the original question, the user had requested the ability to use commas as thousands separators. In a closed as duplicate question, the user had asked how they could apply currency formatting. The following query shows how to perform both tasks. It also demonstrates the application of culture to make this a more generic solution (addressing Tsiridis Dimitris's function to apply Greek special formatting)

-- FORMAT
-- http://msdn.microsoft.com/en-us/library/hh213505(v=sql.110).aspx
-- FORMAT does not do conversion, that's the domain of cast/convert/parse etc
-- Only accepts numeric and date/time data types for formatting. 
--
-- Formatting Types
-- http://msdn.microsoft.com/en-us/library/26etazsy.aspx

-- Standard numeric format strings
-- http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx
SELECT
    -- c => currency
    -- n => numeric
    FORMAT(987654321, N'N', C.culture) AS some_number
,   FORMAT(987654321, N'c', C.culture) AS some_currency
,   C.culture
FROM
    (
        -- Language culture names
        -- http://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx
        VALUES
            ('en-US')
        ,   ('en-GB')
        ,   ('ja-JP')
        ,   ('Ro-RO')
        ,   ('el-GR')
    ) C (culture);

SQLFiddle for the above

Solution 5 - Sql Server

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+.

Solution 6 - Sql Server

Please try with below query:

SELECT FORMAT(987654321,'#,###,##0')

Format with right decimal point :

SELECT FORMAT(987654321,'#,###,##0.###\,###')

Solution 7 - Sql Server

SELECT REPLACE(CONVERT(varchar(20), (CAST(9876543 AS money)), 1), '.00', '')

output= 9,876,543

and you can replace 9876543 by your column name.

Solution 8 - Sql Server

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

Solution 9 - Sql Server

This belongs in a comment to Phil Hunt's answer but alas I don't have the rep.

To strip the ".00" off the end of your number string, parsename is super-handy. It tokenizes period-delimited strings and returns the specified element, starting with the rightmost token as element 1.

SELECT PARSENAME(CONVERT(varchar, CAST(987654321 AS money), 1), 2)

Yields "987,654,321"

Solution 10 - Sql Server

here is another t-sql UDF

CREATE FUNCTION dbo.Format(@num int)
returns varChar(30)
As
Begin
Declare @out varChar(30) = ''

  while @num > 0 Begin
      Set @out = str(@num % 1000, 3, 0) + Coalesce(','+@out, '')
      Set @num = @num / 1000
  End
  Return @out
End

Solution 11 - Sql Server

`/* 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')`

Solution 12 - Sql Server

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

Solution 13 - Sql Server

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

Solution 14 - Sql Server

/*
  #------------------------------------------------------------------------#
  #            SQL Query Script                                            #
  #            ----------------                                            #
  # Funcion.:  dbo.fn_nDerecha ( Numero, Pos_Enteros, Pos_Decimales )      #
  #    Numero        : es el Numero o Valor a formatear                    #
  #    Pos_Enteros   : es la cantidad posiciones para Enteros              #
  #    Pos_Decimales : es la cantidad posiciones para Decimales            #
  #                                                                        #
  # OBJETIVO:  Formatear los Numeros con Coma y Justificado a la Derecha   #
  #  Por Ejemplo:                                                          #
  #   dbo.fn_nDerecha ( Numero, 9, 2 )         Resultado = ---,---,--9.99  #
  #               dado  Numero = 1234.56       Resultado =       1,234.56  #
  #               dado  Numero = -1.56         Resultado =          -1.56  #
  #               dado  Numero = -53783423.56  Resultado = -53,783,423.56  #
  #                                                                        #
  # Autor...:  Francisco Eugenio Cabrera Perez                             #
  # Fecha...:  Noviembre 25, 2015                                          #
  # Pais....:  Republica Dominicana                                        #
  #------------------------------------------------------------------------#
*/



CREATE FUNCTION [dbo].[fn_nDerecha]
(
    -- Agregue Argumentos, para personalizar la funcion a su conveniencia
    @Numero_str    varchar(max)
   ,@Pos_Enteros   int
   ,@Pos_Decimales int
)
RETURNS varchar(max)
AS
BEGIN
  --  Declare la variable del RETURN aqui, en este caso es RESULT
  declare @RESULTADO varchar(max)
  set     @RESULTADO = '****'

  -----------------------------------------------  --
  declare @Numero_num numeric(28,12)
  set     @Numero_num =
  (
  case when isnumeric(@Numero_str) = 0 
       then 0
       else round (convert( numeric(28,12), @Numero_str), @Pos_Decimales)
  end
  )
  --  -----------------------------------------------  --
  --  Aumenta @Pos_Enteros de @RESULTADO,
  --      si las posiciones de Enteros del dato @Numero_str es Mayor...
  --
  declare   @Num_Pos_Ent int
  set       @Num_Pos_Ent = len ( convert( varchar, convert(int, abs(@Numero_num) ) ) )
  --
  declare   @Pos_Ent_Mas int
  set       @Pos_Ent_Mas =
  (
  case when @Num_Pos_Ent > @Pos_Enteros
       then @Num_Pos_Ent - @Pos_Enteros
       else 0
  end
  )
  set       @Pos_Enteros = @Pos_Enteros + @Pos_Ent_Mas
  --
  --  -----------------------------------------------  --
  declare @p_Signo_ctd       int
  set     @p_Signo_ctd       = (case when @Numero_num < 1 then 1 else 0 end)
  --
  declare @p_Comas_ctd       int
  set     @p_Comas_ctd       = ( @Pos_Enteros - 1 ) / 3
  --
  declare @p_Punto_ctd       int
  set     @p_Punto_ctd       = (case when @Pos_Decimales > 0 then 1 else 0 end)
  --
  declare @p_input_Longitud  int
  set     @p_input_Longitud  = ( @p_Signo_ctd + @Pos_Enteros ) +
                                 @p_Punto_ctd + @Pos_Decimales
  --
  declare @p_output_Longitud int
  set     @p_output_Longitud = ( @p_Signo_ctd + @Pos_Enteros   + @p_Comas_ctd )
                             + ( @p_Punto_ctd + @Pos_Decimales )
  --
  --  ===================================================================  --


  declare @Valor_str varchar(max)
  set     @Valor_str = str(@Numero_num, @p_input_Longitud, @Pos_Decimales)

  declare @V_Ent_str varchar(max)
  set     @V_Ent_str = 
  (case when @Pos_Decimales > 0 
        then substring( @Valor_str, 0, charindex('.', @Valor_str, 0) )
        else            @Valor_str end)
  --
  declare @V_Dec_str varchar(max)
  set     @V_Dec_str = 
  (case when @Pos_Decimales > 0 
        then '.' + right(@Valor_str, @Pos_Decimales)
        else '' end)
  --
  set @V_Ent_str = convert(VARCHAR, convert(money, @V_Ent_str), 1) 
  set @V_Ent_str = substring( @V_Ent_str, 0, charindex('.', @V_Ent_str, 0) )
  --


  set @RESULTADO    = @V_Ent_str + @V_Dec_str 
  --
  set @RESULTADO = ( replicate( ' ', @p_output_Longitud - len(@RESULTADO) ) + @RESULTADO )
  --

  --  ===================================================================  -
  --  ===================================================================  -

-

  RETURN @RESULTADO
END

  --  ===================================================================  --

/* This function needs 3 arguments: the First argument is the @Numero_str which the Number as data input, and the other 2 arguments specify how the information will be formatted for the output, those arguments are @Pos_Enteros and @Pos_Decimales which specify how many Integers and Decimal places you want to show for the Number you pass as input argument. */

Solution 15 - Sql Server

For SQL Server before 2012 which does not include the FORMAT function, create this function:

CREATE FUNCTION FormatCurrency(@value numeric(30,2))
    RETURNS varchar(50)
    AS
    BEGIN
	    DECLARE @NumAsChar VARCHAR(50)
	    SET @NumAsChar = '$' + CONVERT(varchar(50), CAST(@Value AS money),1)
	    RETURN @NumAsChar
    END 

select dbo.FormatCurrency(12345678) returns $12,345,678.00

Drop the $ if you just want commas.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionmattmc3View Question on Stackoverflow
Solution 1 - Sql ServerThomas MuellerView Answer on Stackoverflow
Solution 2 - Sql ServerPhil HuntView Answer on Stackoverflow
Solution 3 - Sql ServerzomfView Answer on Stackoverflow
Solution 4 - Sql ServerbillinkcView Answer on Stackoverflow
Solution 5 - Sql ServerContangoView Answer on Stackoverflow
Solution 6 - Sql ServerTiến DũngView Answer on Stackoverflow
Solution 7 - Sql Serverhojjat.miView Answer on Stackoverflow
Solution 8 - Sql Serverhavana59erView Answer on Stackoverflow
Solution 9 - Sql ServerApoxyView Answer on Stackoverflow
Solution 10 - Sql ServerCharles BretanaView Answer on Stackoverflow
Solution 11 - Sql ServerTsiridis DimitrisView Answer on Stackoverflow
Solution 12 - Sql Serveruser2230239View Answer on Stackoverflow
Solution 13 - Sql ServerMitchell StilesView Answer on Stackoverflow
Solution 14 - Sql ServerFrancisco CabreraView Answer on Stackoverflow
Solution 15 - Sql ServerStevenJeView Answer on Stackoverflow