Bagaimana cara memformat angka dengan koma di T-SQL?

198

Saya menjalankan beberapa pertanyaan administratif dan menyusun hasil dari sp_spaceuseddi SQL Server 2008 untuk melihat rasio ruang data / indeks dari beberapa tabel dalam database saya. Tentu saja saya mendapatkan segala macam hasil dalam jumlah besar dan mata saya mulai tertutup. Akan sangat nyaman jika saya bisa memformat semua angka itu dengan koma (987654321 menjadi 987.654.321). Lucu bahwa selama bertahun-tahun saya telah menggunakan SQL Server, masalah ini tidak pernah muncul karena sebagian besar waktu saya akan melakukan format pada lapisan presentasi, tetapi dalam hal ini hasil T-SQL dalam SSMS adalah presentasi.

Saya telah mempertimbangkan hanya membuat UDR CLR sederhana untuk menyelesaikan ini, tetapi sepertinya ini harus dilakukan di T-SQL lama. Jadi, saya akan mengajukan pertanyaan di sini - bagaimana Anda melakukan pemformatan numerik dalam vanilla T-SQL?

mattmc3
sumber
7
Apakah "Laporan -> Penggunaan Disk berdasarkan Tabel" melakukan apa yang Anda butuhkan dengan cara yang cukup estetis?
Martin Smith
1
@ Martin - Benar-benar luar biasa! Bahkan tidak tahu itu ada. Saya telah membawa beberapa skrip DBA saya selama hampir satu dekade, jadi saya melewatkan semuanya. Namun, saya pikir pertanyaan ini adalah bagian penting dari basis pengetahuan T-SQL pada stackoverflow, tetapi untuk masalah khusus saya ini sangat berguna.
mattmc3
8
Dengan SQL Server 2012 + Anda dapat menggunakan fungsi FORMAT (). mis. '#, ##. 000' msdn.microsoft.com/en-us/library/hh213505.aspx
Volvox

Jawaban:

184

Di SQL Server 2012 dan lebih tinggi, ini akan memformat angka dengan koma:

select format([Number], 'N0')

Anda juga dapat mengubah 0ke jumlah tempat desimal yang Anda inginkan.

Thomas Mueller
sumber
16
Ini sekarang jawaban terbaik sejak diperkenalkannya formatfungsi.
mattmc3
ada baiknya memperhatikan parameter ketiga (opsional) culture.
Samuele Colombo
Ditentukan OP SQL Server 2008
foremaro
254

Sementara saya setuju dengan semua orang, termasuk OP, yang mengatakan bahwa pemformatan harus dilakukan di lapisan presentasi, pemformatan ini dapat diselesaikan dalam T-SQL dengan melakukan casting ke moneydan kemudian mengonversi ke varchar. Ini tidak termasuk desimal jejak, yang bisa dilumpuhkan dengan SUBSTRING.

SELECT CONVERT(varchar, CAST(987654321 AS money), 1)
Phil Hunt
sumber
12
Meskipun saya setuju bahwa pemformatan secara umum harus terjadi di tempat lain, kita semua menganggap fungsi pemformatan tanggal begitu saja. Penyisipan koma dapat dilakukan seperti yang ditunjukkan di sini. +1.
EBarr
4
Namun, ini tidak berfungsi untuk gaya pemformatan mony lainnya. Di Swiss kami menulis Uang misalnya dalam bentuk ini: 987'654'321.00 Bagaimana melakukannya?
Daniel
6
Anda dapat mengganti SELECT REPLACE (CONVERT (varchar, CAST (987654321 AS money), 1), ',', '' ''
Hoody
4
Meskipun saya setuju bahwa pemformatan harus dilakukan di lapisan presentasi jika memungkinkan, pasti ada waktu, seperti dengan peringatan Ignite / DPA, bahwa email yang saya terima adalah lapisan presentasi. Satu-satunya cara untuk menempatkan koma di tempat seperti itu adalah melalui SQL. Memiliki koma dalam jumlah besar sangat membantu dalam kasus tersebut.
PseudoToad
1
Semua orang ingin memberi tahu Anda apa yang "harus" dilakukan, tetapi bukan itu yang dimaksud dengan mendesain kode Anda sendiri. Jika setiap orang hanya melakukan apa yang "harus" dilakukan, maka kita kehilangan semangat penemuan dan kemampuan untuk meretas berbagai hal bersama untuk menyelesaikan masalah dengan cepat dengan sedikit keributan dan upaya.
Geoff Griswald
59

Saya akan merekomendasikan Ganti sebagai pengganti Substring untuk menghindari masalah panjang string:

REPLACE(CONVERT(varchar(20), (CAST(SUM(table.value) AS money)), 1), '.00', '')
zomf
sumber
3
Meskipun konversi uang tidak boleh berubah, saya suka jaminan tidak keluar batas yang Ganti tawaran atas Substring.
Sean
48

Untuk implementasi SQL Server 2012+, Anda akan memiliki kemampuan untuk menggunakan FORMAT untuk menerapkan pemformatan string ke tipe data non-string.

Dalam pertanyaan awal, pengguna meminta kemampuan untuk menggunakan koma sebagai ribuan pemisah. Dalam pertanyaan tertutup sebagai duplikat , pengguna telah bertanya bagaimana mereka dapat menerapkan pemformatan mata uang. Kueri berikut menunjukkan cara melakukan kedua tugas. Ini juga menunjukkan penerapan budaya untuk menjadikan ini solusi yang lebih umum (membahas fungsi Tsiridis Dimitris untuk menerapkan format khusus Yunani)

-- 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 untuk hal di atas

billinkc
sumber
1
Bagian yang hebat, ini akan sangat berguna :)
jediCouncilor
1
Fiddle rusak, katanya sekarangString index out of range: 33
Jeff Puckett
1
@ JeffPuckettII Ya, sangat disayangkan biola untuk SQL Server tidak lagi berfungsi. Untungnya, Anda harus dapat menempelkan di atas ke alat permintaan apa pun yang terhubung ke SQL Server 2012+
billinkc
20

Demo 1

Menunjukkan penambahan koma:

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

Demo 2

Menunjukkan koma dan titik desimal. Perhatikan bahwa ia membulatkan angka terakhir jika perlu.

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

Kesesuaian

SQL Server 2012+.

Contango
sumber
2
Ini adalah salah satunya! Bekerja dengan len (kolom) dan juga kolom - sedangkan solusi 2012+ lain yang saya coba tidak lakukan.
Graham Laight
1
Bagus! Ini adalah jawaban yang saya cari (untuk digunakan dengan T-SQL, termasuk pada SEDE )
ashleedawg
10

Silakan coba dengan kueri di bawah ini:

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

Format dengan titik desimal kanan:

SELECT FORMAT(987654321,'#,###,##0.###\,###')
Tiến Dũng
sumber
3
Ya, cara yang sekarang kita miliki FORMATfungsinya adalah SELECT format(123456789987654321,'###,##0'), atau lebih sederhana, select format(123456789987654321, 'N0')seperti yang dijawab oleh @ThomasMueller.
mattmc3
FORMAT adalah mimpi buruk kinerja - Anda mulai menggunakannya dan bergantung padanya, lalu menemukan bahwa basis data Anda tidak dapat ditingkatkan. Dan sekarang ini dibangun ke dalam selusin fitur dan Anda tidak dapat menghindarinya. Jangan pernah gunakan FORMAT.
Pxtl
9
SELECT REPLACE(CONVERT(varchar(20), (CAST(9876543 AS money)), 1), '.00', '')

output = 9.876.543

dan Anda dapat mengganti 9876543 dengan nama kolom Anda.

hojjat.mi
sumber
7

Mencoba trik uang di atas, dan ini berfungsi baik untuk nilai numerik dengan dua atau kurang angka signifikan. Saya membuat fungsi saya sendiri untuk memformat angka dengan desimal:

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

Ini termasuk dalam komentar untuk jawaban Phil Hunt tetapi sayangnya saya tidak memiliki perwakilan.

Untuk menghapus "0,00" di bagian akhir string angka Anda, nama samaran sangat berguna. Ini tokenizes string dibatasi periode dan mengembalikan elemen yang ditentukan, dimulai dengan token paling kanan sebagai elemen 1.

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

Menghasilkan "987.654.321"

Apoksi
sumber
3

di sini adalah UDF t-sql lain

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

Berikut ini adalah fungsi skalar yang saya gunakan yang memperbaiki beberapa bug pada contoh sebelumnya (di atas) dan juga menangani nilai desimal (ke # digit yang ditentukan) (DITERBITKAN juga bekerja dengan 0 & angka negatif). Satu catatan lain, pemeran sebagai metode uang di atas terbatas pada ukuran tipe data MONEY, dan tidak berfungsi dengan 4 (atau lebih) desimal digit. Metode itu jelas lebih sederhana tetapi kurang fleksibel.

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
pengguna2230239
sumber
1

UDF lain yang semoga cukup generik dan tidak membuat asumsi tentang apakah Anda ingin membulatkan ke tempat desimal tertentu:

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

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

/ * Fungsi ini membutuhkan 3 argumen: argumen pertama adalah @Numero_str yang nomor sebagai input data, dan 2 argumen lainnya menentukan bagaimana informasi akan diformat untuk output, argumen tersebut adalah @Pos_Enteros dan @Pos_Decimales yang menentukan berapa banyak Bilangan bulat dan Desimal yang ingin Anda tunjukkan untuk Angka yang Anda berikan sebagai argumen masukan. * /

Francisco Cabrera
sumber
0

Untuk SQL Server sebelum 2012 yang tidak termasuk fungsi FORMAT, buat fungsi ini:

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 

pilih dbo.FormatCurrency (12345678) mengembalikan $ 12.345.678,00

Jatuhkan $ jika Anda hanya ingin koma.

StevenJe
sumber