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

198

J'exécute des requêtes administratives et compile les résultats à partir sp_spaceusedde SQL Server 2008 pour examiner les ratios d'espace données / index de certaines tables de ma base de données. Bien sûr, j'obtiens toutes sortes de chiffres dans les résultats et mes yeux commencent à passer sous silence. Ce serait vraiment pratique si je pouvais formater tous ces nombres avec des virgules (987654321 devient 987,654,321). C'est drôle que depuis de nombreuses années que j'utilise SQL Server, ce problème ne se soit jamais posé depuis la plupart du temps, je ferais du formatage 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 simplement créer un UDF CLR simple pour résoudre ce problème, mais il semble que cela devrait être faisable dans le vieux T-SQL. Donc, je vais poser la question ici - comment faites-vous le formatage numérique dans vanilla T-SQL?

mattmc3
la source
7
Est-ce que "Rapports -> Utilisation du disque par table" fait ce dont vous avez besoin d'une manière assez esthétique?
Martin Smith
1
@Martin - Vraiment génial! Je ne savais même pas que ça existait. J'ai emporté certains de mes scripts DBA avec moi pendant près d'une décennie, donc j'ai complètement raté ça. Pourtant, je pense que cette question est une partie importante de la base de connaissances T-SQL sur stackoverflow, mais pour mon problème spécifique, c'est vraiment pratique.
mattmc3
8
Avec SQL Server 2012 +, vous pouvez utiliser la fonction FORMAT (). par exemple '#, ##. 000' msdn.microsoft.com/en-us/library/hh213505.aspx
Volvox

Réponses:

184

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

select format([Number], 'N0')

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

Thomas Mueller
la source
16
C'est maintenant la meilleure réponse depuis l'introduction de la formatfonction.
mattmc3
il convient de noter le troisième paramètre (facultatif) culture.
Samuele Colombo
OP spécifié SQL Server 2008
foremaro
254

Bien que je sois d'accord avec tout le monde, y compris l'OP, qui dit que la mise en forme doit être effectuée dans la couche de présentation, cette mise en forme peut être effectuée dans T-SQL en moneyconvertissant en puis en convertissant en varchar. Cela inclut les décimales de fin, cependant, qui pourraient être bouclées SUBSTRING.

SELECT CONVERT(varchar, CAST(987654321 AS money), 1)
Phil Hunt
la source
12
Bien que je convienne que le formatage devrait généralement se produire ailleurs, nous prenons tous pour acquis les fonctions de formatage de la date. L'insertion de virgule peut être effectuée comme indiqué ici. +1.
EBarr
4
Cependant, cela ne fonctionne pas pour les autres styles de formatage monétaire. En Suisse, nous écrivons par exemple Money sous cette forme: 987'654'321.00 Comment faire?
Daniel
6
Vous pouvez faire un remplacement SELECT REPLACE (CONVERT (varchar, CAST (987654321 AS money), 1), ',', '' '')
Sweat
4
Bien que je convienne que la mise en forme doit être effectuée dans la couche de présentation lorsque cela est possible, il y a certainement des moments, comme avec les alertes Ignite / DPA, que l'e-mail que je reçois est la couche de présentation. La seule façon de placer des virgules dans un endroit comme celui-ci est via SQL. Avoir des virgules en grand nombre est extrêmement utile dans ces cas.
PseudoToad
1
Tout le monde veut vous dire ce qui «devrait» être fait, mais ce n'est pas de cela qu'il s'agit de concevoir votre propre code. Si tout le monde ne fait que ce qui "devrait" être fait, nous perdons alors cet esprit d'inventivité et cette capacité à pirater les choses ensemble pour résoudre rapidement un problème avec un minimum d'efforts et d'efforts.
Geoff Griswald
59

Je recommande de remplacer au lieu de sous-chaîne pour éviter les problèmes de longueur de chaîne:

REPLACE(CONVERT(varchar(20), (CAST(SUM(table.value) AS money)), 1), '.00', '')
zomf
la source
3
Même si la conversion monétaire ne devrait jamais changer, j'aime la garantie de ne pas sortir des limites que Remplace propose sur Substring.
Sean
48

Pour les implémentations SQL Server 2012+, vous aurez la possibilité d'utiliser le FORMAT pour appliquer le formatage de chaîne aux types de données non-chaîne.

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

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

billinkc
la source
1
Grande part, cela sera utile :)
jediCouncilor
1
Le violon est cassé, dit maintenantString index out of range: 33
Jeff Puckett
1
@JeffPuckettII Oui, c'est dommage que le violon pour SQL Server ne fonctionne plus. Heureusement, vous devriez pouvoir coller ce qui précède dans n'importe quel outil de requête connecté à SQL Server 2012+
billinkc
20

Démo 1

Démontre l'ajout de virgules:

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

Démo 2

Montre les virgules et les décimales. Observez 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+.

Contango
la source
2
C'est la bonne! Fonctionne avec len (colonne) ainsi que simplement la colonne - contrairement à une autre solution 2012+ que j'ai essayée.
Graham Laight
1
Génial! C'est la réponse que je cherchais (pour une utilisation avec T-SQL, y compris sur SEDE )
ashleedawg
10

Veuillez essayer avec la requête ci-dessous:

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

Format avec virgule décimale droite:

SELECT FORMAT(987654321,'#,###,##0.###\,###')
Tiến Dũng
la source
3
Oui, la bonne façon maintenant que nous avons la FORMATfonction est SELECT format(123456789987654321,'###,##0'), ou plus simplement, select format(123456789987654321, 'N0')comme @ThomasMueller a répondu.
mattmc3
FORMAT est un cauchemar de performance - vous commencez à l'utiliser et en dépendez, puis constatez que votre base de données ne peut pas évoluer. Et maintenant, il est intégré à une douzaine de fonctionnalités et vous ne pouvez y échapper. N'utilisez jamais FORMAT.
Pxtl
9
SELECT REPLACE(CONVERT(varchar(20), (CAST(9876543 AS money)), 1), '.00', '')

sortie = 9,876,543

et vous pouvez remplacer 9876543 par le nom de votre colonne.

hojjat.mi
la source
7

J'ai essayé l'astuce de l'argent ci-dessus, et cela fonctionne très bien pour les valeurs numériques avec deux chiffres ou moins significatifs. J'ai créé ma propre fonction pour formater les 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
havana59er
la source
4

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

Pour retirer le ".00" de la fin de votre chaîne numérique, le parsename est très pratique. Il tokenise les chaînes délimitées par des points et renvoie l'élément spécifié, en commençant par le token le plus à droite comme élément 1.

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

Donne "987 654 321"

Apoxy
la source
3

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

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

Un autre UDF qui, espérons-le, est assez générique et ne fait pas d'hypothèses quant à savoir si 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
Mitchell Stiles
la source
0
/*
  #------------------------------------------------------------------------#
  #            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 a besoin de 3 arguments: le premier argument est le @Numero_str dont le nombre comme entrée de données, et les 2 autres arguments spécifient comment les informations seront formatées 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 passez comme argument d'entrée. * /

Francisco Cabrera
la source
0

Pour SQL Server avant 2012 qui n'inclut pas la fonction FORMAT, créez cette fonction:

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 

sélectionnez dbo.FormatCurrency (12345678) renvoie 12 345 678,00 $

Déposez le $ si vous voulez juste des virgules.

StevenJe
la source