T-SQL'de bir sayıyı virgülle nasıl biçimlendiririm?


202

Bazı yönetimsel sorguları çalıştırıyorum ve sp_spaceusedveritabanımdaki bazı tabloların veri / dizin alanı oranlarına bakmak için SQL Server 2008'deki sonuçları derliyorum . Tabii ki sonuçlarda her türlü büyük sayıyı alıyorum ve gözlerim parlamaya başlıyor. Tüm bu sayıları virgülle biçimlendirebilseydim çok uygun olurdu (987654321, 987,654,321 olur). Komik çoğu zaman sunum katmanında biçimlendirme yapıyor olurdu çünkü SQL Server kullandığınız tüm yıllardır bu sorun ortaya olmamıştı, ancak bu durumda SSMS T-SQL sonucu olduğunu olduğunu sunumu.

Bunu çözmek için sadece basit bir CLR UDF oluşturmayı düşündüm, ancak bu sadece düz eski T-SQL'de yapılabilecek gibi görünüyor. Peki, burada soru soracağım - vanilya T-SQL'de sayısal biçimlendirme nasıl yapılır?


7
"Raporlar -> Tabloya Göre Disk Kullanımı" ihtiyacınız olanı estetik açıdan yeterince memnun ediyor mu?
Martin Smith

1
@Martin - Gerçekten harika! Bunun var olduğunu bile bilmiyordum. DBA senaryolarımın bir kısmını yaklaşık on yıldır yanımda taşıyorum, bu yüzden tamamen kaçırdım. Yine de, bu sorunun stackoverflow'daki T-SQL bilgi tabanının önemli bir parçası olduğunu düşünüyorum, ancak özel sorunum için bu gerçekten kullanışlı.
mattmc3

8
SQL Server 2012 + ile FORMAT () işlevini kullanabilirsiniz. örneğin '#, ##. 000' msdn.microsoft.com/tr-tr/library/hh213505.aspx
Volvox

Yanıtlar:


188

SQL Server 2012 ve sonraki sürümlerde, bu sayı virgülle biçimlendirilir:

select format([Number], 'N0')

İstediğiniz 0ondalık basamak sayısını da değiştirebilirsiniz .


16
Bu şimdi formatfonksiyonun tanıtılmasından bu yana en iyi cevaptır .
mattmc3

üçüncü (isteğe bağlı) parametreyi fark etmeye değer culture.
Samuele Colombo

OP SQL Server 2008'i belirledi
foremaro

254

Biçimlendirme sunum katmanında yapılması gerektiğini söyleyen OP dahil herkese katılıyorum, ancak bu biçimlendirme T-SQL'de döküm yapıp moneysonra dönüştürülerek gerçekleştirilebilir varchar. Bu, ilmekli olabilen sondaki ondalık sayıları da içerir SUBSTRING.

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

12
Genel olarak biçimlendirmenin başka bir yerde olması gerektiğini kabul etsem de, hepimiz tarih biçimlendirme işlevlerini kabul ediyoruz. Virgül ekleme burada gösterildiği gibi yapılabilir. +1.
EBarr

4
Ancak, bu diğer mony-biçimlendirme stilleri için çalışmaz. İsviçre'de Para'yı şu biçimde yazarız: 987'654'321.00 Bunu nasıl yapabilirim?
Daniel

6
Bir değiştirme SELECT REPLACE (CONVERT (varchar, CAST (987654321 AS para)), 1), ',', '' '') yapabilirsiniz
Hoody

4
Biçimlendirmenin mümkün olduğunda sunum katmanında yapılması gerektiğini kabul etsem de, Ignite / DPA uyarıları gibi, aldığım e-postanın sunum katmanı olduğu gibi kesinlikle zamanlar vardır. Bunun gibi bir yere virgül koymanın tek yolu SQL'dir. Çok sayıda virgül bulundurmak bu durumlarda olağanüstü yardımcı olur.
PseudoToad

1
Herkes size ne yapılması gerektiğini söylemek ister, ancak kendi kodunuzu tasarlamak bu değildir. Eğer herkes sadece "yapılması gerekeni" yaptıysa, o zaman bir münasebet ruhu ve bir sorunu en az karışıklık ve çabayla çabucak çözmek için bir araya gelme yeteneğini kaybederiz.
Geoff Griswald

59

Dize uzunluğu sorunları önlemek için Substring yerine Değiştir öneriyoruz:

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

3
Para dönüşümü hiç değişmese de, Substring üzerinden Replace'ın sunduğu sınırların dışına çıkmama garantisini seviyorum.
Sean

48

SQL Server 2012+ uygulamalar için, kullanmak yeteneğine sahip olacak FORMAT olmayan dize veri türlerine biçimlendirme dize uygulamak.

Orijinal soruda, kullanıcı virgüllerin binlerce ayırıcı olarak kullanılmasını istemişti. Yinelenen kapalı bir soruda , kullanıcı para birimi biçimlendirmesini nasıl uygulayabileceklerini sormuştu. Aşağıdaki sorgu her iki görevin nasıl gerçekleştirileceğini gösterir. Ayrıca bunu daha genel bir çözüm haline getirmek için kültürün uygulanmasını da gösteriyor (Tsiridis Dimitris'in Yunan özel biçimlendirmesini uygulama işlevini ele alıyor)

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

Yukarıdakiler için SQLFiddle


1
Harika paylaşım, bu kullanışlı olacak :)
jediCouncilor

1
Keman bozuldu, şimdi diyorString index out of range: 33
Jeff Puckett

1
@JeffPuckettII Evet, SQL Server'ın kemanının artık çalışmaması üzücü. Neyse ki, yukarıdakileri SQL Server 2012+ ile bağlantılı herhangi bir sorgu aracına yapıştırabilmelisiniz
billinkc

20

Demo 1

Virgül eklemeyi gösterir:

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

Demo 2

Virgül ve ondalık basamak gösterir. Gerekirse son basamağı yuvarladığını gözlemleyin.

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

uygunluk

SQL Server 2012+.


2
İşte bu o! Len (sütun) yanı sıra sadece sütun ile çalışır - oysa ben denedim başka bir 2012 + çözüm yoktu.
Graham Laight

1
Harika! Bu (dahil T-SQL ile kullanmak için aradığım cevabı üzerine Sede )
ashleedawg

10

Lütfen aşağıdaki sorguyu deneyin:

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

Sağ ondalık nokta ile biçimlendirme:

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

3
Evet, şimdi bu FORMATişleve sahip olmamızın doğru yolu SELECT format(123456789987654321,'###,##0')ya da daha basit bir select format(123456789987654321, 'N0')şekilde @ThomasMueller'in yanıtladığı gibidir.
mattmc3

FORMAT bir performans kabusu - kullanmaya başlıyorsunuz ve ona bağlısınız, sonra veritabanınızın ölçeklenemediğini görüyorsunuz. Ve şimdi bir düzine özelliğe yerleştirildi ve bundan kaçamazsınız. Asla FORMAT kullanmayın.
Pxtl

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

çıktı = 9.876.543

9876543'ü sütun adınızla değiştirebilirsiniz.


7

Yukarıdaki para hilesini denedim ve bu, iki veya daha az önemli basamaklı sayısal değerler için harika çalışıyor. Sayıları ondalık sayılarla biçimlendirmek için kendi işlevimi oluşturdum:

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

4

Bu Phil Hunt'ın cevabına yapılan bir yorumda yer alıyor ama ne yazık ki temsilcisi yok.

".00" kodunu sayı dizenizin sonundan kaldırmak için parsename çok kullanışlıdır. Periyotla sınırlandırılmış dizeleri işaretler ve öğe 1 olarak en sağ işaretle başlayarak belirtilen öğeyi döndürür.

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

"987.654.321"


3

İşte başka bir 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

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

1

Bir önceki örnekte (yukarıda) bazı hataları gideren ve ayrıca ondalık değerleri (belirtilen basamak sayısına) işleyen (0 ve negatif sayılarla da çalışmak için EDİTİLDİ) kullandığım bir skaler fonksiyon. Bir başka not, yukarıdaki para olarak yayınlama yöntemi, MONEY veri türünün boyutuyla sınırlıdır ve 4 (veya daha fazla) basamaklı ondalık sayılarla çalışmaz. Bu yöntem kesinlikle daha basit ama daha az esnektir.

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

Umarım yeterince genel olan ve belirli sayıda ondalık basamağa yuvarlamak isteyip istemediğiniz konusunda varsayımlarda bulunmayan başka bir 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

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

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

/ * Bu işlev 3 bağımsız değişkene ihtiyaç duyar: İlk bağımsız değişken, veri girişi olarak Sayı'nın @Numero_str ve diğer 2 bağımsız değişken, bilgilerin çıktı için nasıl biçimlendirileceğini belirtir; bu bağımsız değişkenler @Pos_Enteros ve @Pos_Decimales olur. Girdi bağımsız değişkeni olarak ilettiğiniz Sayı için göstermek istediğiniz Tamsayılar ve Ondalık basamaklar. * /


0

FORMAT işlevini içermeyen 2012'den önceki SQL Server için bu işlevi oluşturun:

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 

dbo.FormatCurrency (12345678) $ 12,345,678.00 döndürür

Sadece virgül istiyorsanız $ bırakın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.