web-dev-qa-db-fra.com

Comment formater un nombre avec des virgules dans T-SQL?

J'exécute des requêtes administratives et compile les résultats de sp_spaceused dans SQL Server 2008 pour examiner les ratios d'espace données/index de certaines tables de ma base de données. Bien sûr, je reçois toutes sortes de chiffres en grand nombre dans les résultats et mes yeux commencent à briller de mille feux. Ce serait vraiment pratique si je pouvais formater tous ces nombres avec des virgules (987654321 devient 987,654,321). C'est drôle que pendant toutes les années où j'ai utilisé SQL Server, ce problème ne se soit jamais posé car je formais la plupart du temps au niveau de la couche de présentation, mais dans ce cas, le résultat T-SQL dans SSMS est la présentation.

J'ai envisagé de créer simplement un fichier UDF CLR simple pour résoudre ce problème, mais il semble que cela devrait être réalisable dans le vieux T-SQL. Je vais donc poser la question suivante: comment formater le format numérique dans Vanilla T-SQL?

174
mattmc3

Dans SQL Server 2012 et versions ultérieures, cela formate un nombre avec des virgules:

select format([Number], 'N0')

Vous pouvez également remplacer 0 par le nombre de décimales souhaité.

130
Thomas Mueller

Bien que je sois d’accord avec tout le monde, y compris le PO, qui dit que le formatage doit être effectué dans la couche de présentation, ce formatage peut être effectué dans T-SQL en convertissant en money, puis en convertissant en varchar. Cela inclut les décimales de fin, cependant, qui pourraient être bouclées avec SUBSTRING.

SELECT CONVERT(varchar, CAST(987654321 AS money), 1)
250
Phil Hunt

Je vous recommande de remplacer à la place de Substring pour éviter les problèmes de longueur de chaîne:

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

Pour les implémentations de SQL Server 2012+, vous pourrez utiliser le FORMAT pour appliquer le formatage de chaîne à des types de données autres que des chaînes.

Dans la question initiale, l'utilisateur avait demandé la possibilité d'utiliser des virgules comme séparateurs de milliers. Dans un question fermée en double , l'utilisateur avait demandé comment il pouvait appliquer le formatage monétaire. La requête suivante montre comment effectuer les deux tâches. Cela démontre également l'application de la culture pour en faire une solution plus générique (adressant la fonction de Tsiridis Dimitris d'appliquer un formatage spécial grec)

-- 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 pour ce qui précède

46
billinkc

Démo 1

Montre comment ajouter des virgules:

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

Démo 2

Montre des virgules et des points décimaux. Notez qu’il arrondit le dernier chiffre si nécessaire.

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

Compatibilité

SQL Server 2012+.

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

sortie = 9 876 543

et vous pouvez remplacer 9876543 par votre nom de colonne.

9
hojjat.mi

Veuillez essayer avec la requête ci-dessous:

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

Format avec point décimal à droite:

SELECT FORMAT(987654321,'#,###,##0.###\,###')
9
Tiến Dũng

J'ai essayé le truc d'argent ci-dessus, et cela fonctionne très bien pour les valeurs numériques avec deux chiffres significatifs ou moins. J'ai créé ma propre fonction pour formater des nombres avec des décimales:

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
havana59er

Cela appartient à un commentaire de la réponse de Phil Hunt mais hélas je n'ai pas le représentant.

Pour supprimer le ".00" de la fin de votre chaîne numérique, le parsename est extrêmement pratique. Il marque les chaînes délimitées par des périodes et renvoie l'élément spécifié, en commençant par le jeton le plus à droite en tant qu'élément 1.

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

Les rendements "987,654,321"

4
Apoxy

voici un autre UDF t-sql

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
3
Charles Bretana
`/* 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')`
2
Tsiridis Dimitris

Voici une fonction scalaire que j'utilise qui corrige quelques bugs dans un exemple précédent (ci-dessus) et gère également les valeurs décimales (en fonction du nombre de chiffres spécifié) (EDITED fonctionne également avec les nombres 0 et négatifs). Autre remarque, la méthode de conversion en tant qu’argent ci-dessus est limitée à la taille du type de données MONEY et ne fonctionne pas avec 4 décimales (ou plus). Cette méthode est nettement plus simple mais moins 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
1
user2230239

Un autre fichier UDF qui, espérons-le, est suffisamment générique et ne suppose pas que vous voulez arrondir à un nombre spécifique de décimales:

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
1
Mitchell Stiles
/*
  #------------------------------------------------------------------------#
  #            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

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

/ * Cette fonction nécessite 3 arguments: le premier argument est le @Numero_str dont le numéro est une entrée de données et les 2 autres arguments spécifient comment l'information sera formatée pour la sortie, ces arguments sont @Pos_Enteros et @Pos_Decimales qui spécifient combien Entiers et décimales que vous souhaitez afficher pour le nombre que vous transmettez en tant qu'argument d'entrée. * /

0
Francisco Cabrera