简体   繁体   English

如何在T-SQL中用逗号格式化数字?

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

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. 我正在运行一些管理查询,并编译SQL Server 2008中sp_spaceused结果,以查看数据库中某些表的数据/索引空间比率。 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). 如果我可以用逗号将所有这些数字格式化(987654321变为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. 有趣的是,在我多年来一直使用SQL Server的过程中,这个问题从未出现过,因为大多数时候我都会在表示层进行格式化,但是在这种情况下,SSMS中的T-SQL结果就是表示。

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. 我曾经考虑过创建一个简单的CLR UDF来解决这个问题,但是似乎这在纯旧的T-SQL中应该是可行的。 So, I'll pose the question here - how do you do numeric formatting in vanilla T-SQL? 因此,我将在这里提出一个问题-您如何在香草T-SQL中进行数字格式化?

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 . 尽管我同意所有人(包括OP)的意见,包括OP表示应该在表示层中进行格式化,但是可以在T-SQL中通过转换为money然后转换为varchar来完成这种格式化。 This does include trailing decimals, though, that could be looped off with SUBSTRING . 不过,这确实包括尾随的小数,可以用SUBSTRING进行循环。

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

In SQL Server 2012 and higher, this will format a number with commas: 在SQL Server 2012及更高版本中,这将使用逗号格式化数字:

select format([Number], 'N0')

You can also change 0 to the number of decimal places you want. 您也可以将0更改为所需的小数位数。

我建议使用Replace代替Substring来避免字符串长度问题:

REPLACE(CONVERT(varchar(20), (CAST(SUM(table.value) AS money)), 1), '.00', '')

For SQL Server 2012+ implementations, you will have the ability to use the FORMAT to apply string formatting to non-string data types. 对于SQL Server 2012+实现,您将能够使用FORMAT将字符串格式应用于非字符串数据类型。

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) 它还展示了文化的应用,使之成为更通用的解决方案(解决了Tsiridis Dimitris应用希腊特殊格式的功能)

-- 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 上面的SQLFiddle

Demo 1 演示1

Demonstrates adding commas: 演示添加逗号:

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

Demo 2 演示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+ . SQL Server 2012+

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

output= 9,876,543 输出= 9,876,543

and you can replace 9876543 by your column name. 并且您可以将9876543替换为您的列名。

Please try with below query: 请尝试以下查询:

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

Format with right decimal point : 右小数点格式:

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

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

This belongs in a comment to Phil Hunt 's answer but alas I don't have the rep. 这属于对Phil Hunt的回答的评论,但可惜我没有代表。

To strip the ".00" off the end of your number string, parsename is super-handy. 要从数字字符串的末尾去除“ .00”,parsename非常方便。 It tokenizes period-delimited strings and returns the specified element, starting with the rightmost token as element 1. 它标记以句点分隔的字符串并返回指定的元素,从最右边的标记作为元素1开始。

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

Yields "987,654,321" 产量为“ 987,654,321”

here is another t-sql UDF 这是另一个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
`/* 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')`

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). 这是我正在使用的一个标量函数,该函数修复了前面示例中的一些错误(上述),并且还处理了十进制值(达到指定的数字位数)(已编辑,可与0和负数一起使用)。 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. 还有一点需要注意,上面的强制转换为货币方法仅限于MONEY数据类型的大小,并且不适用于4位(或更多位)的小数位数。 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

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: 另一个UDF希望足够通用,并且不会对是否要舍入到小数位数进行假设:

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
/*
  #------------------------------------------------------------------------#
  #            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. / *此函数需要3个参数:第一个参数是@Numero_str,其中Number作为数据输入,另外两个参数指定如何格式化输出信息,这些参数是@Pos_Enteros和@Pos_Decimales,它们指定多少您要显示作为输入参数传递的数字的整数和小数位。 */ * /

For SQL Server before 2012 which does not include the FORMAT function, create this function: 对于不包含FORMAT函数的2012年之前的SQL Server,请创建以下函数:

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 select dbo.FormatCurrency(12345678)返回$ 12,345,678.00

Drop the $ if you just want commas. 如果只需要逗号,请删除$。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM