Làm cách nào để định dạng số bằng dấu phẩy trong T-SQL?


198

Tôi đang chạy một số truy vấn quản trị và biên dịch kết quả từ sp_spaceusedSQL Server 2008 để xem xét tỷ lệ không gian dữ liệu / chỉ mục của một số bảng trong cơ sở dữ liệu của tôi. Tất nhiên tôi đang nhận được tất cả các loại số lượng lớn trong kết quả và đôi mắt của tôi bắt đầu sáng lên. Sẽ thực sự thuận tiện nếu tôi có thể định dạng tất cả các số đó bằng dấu phẩy (987654321 trở thành 987,654,321). Thật buồn cười là trong nhiều năm tôi đã sử dụng SQL Server, vấn đề này chưa bao giờ xuất hiện do hầu hết thời gian tôi sẽ thực hiện định dạng ở lớp trình bày, nhưng trong trường hợp này, kết quả T-SQL trong SSMS bản trình bày.

Tôi đã xem xét việc chỉ tạo một UDF CLR đơn giản để giải quyết vấn đề này, nhưng có vẻ như điều này sẽ có thể thực hiện được trong T-SQL cũ đơn giản. Vì vậy, tôi sẽ đặt ra câu hỏi ở đây - làm thế nào để bạn định dạng số trong vanilla T-SQL?


7
"Báo cáo -> Sử dụng đĩa theo bảng" có làm những gì bạn cần một cách đủ thẩm mỹ không?
Martin Smith

1
@Martin - Thật sự tuyệt vời! Thậm chí không biết rằng đã tồn tại. Tôi đã mang theo một số kịch bản DBA của tôi trong gần một thập kỷ, vì vậy tôi đã hoàn toàn bỏ qua nó. Tuy nhiên, tôi nghĩ rằng câu hỏi này là một phần quan trọng của cơ sở kiến ​​thức T-SQL về stackoverflow, nhưng đối với vấn đề cụ thể của tôi thì điều này thực sự tiện dụng.
mattmc3

8
Với SQL Server 2012 + Bạn có thể sử dụng hàm FORMAT (). ví dụ: '#, ##. 000' msdn.microsoft.com/en-us/l Library / hh213505.aspx
Volvox

Câu trả lời:


184

Trong SQL Server 2012 trở lên, điều này sẽ định dạng một số bằng dấu phẩy:

select format([Number], 'N0')

Bạn cũng có thể thay đổi 0thành số vị trí thập phân bạn muốn.


16
Đây là câu trả lời tốt nhất kể từ khi giới thiệu formatchức năng.
mattmc3

nó đáng chú ý tham số thứ ba (tùy chọn) culture.
Samuele Colombo

OP chỉ định SQL Server 2008
foremaro

254

Mặc dù tôi đồng ý với tất cả mọi người, bao gồm cả OP, người nói rằng định dạng nên được thực hiện trong lớp trình bày, định dạng này có thể được thực hiện trong T-SQL bằng cách chuyển sang moneyvà sau đó chuyển đổi sang varchar. Điều này không bao gồm các số thập phân kéo dài, tuy nhiên, có thể được lặp đi lặp lại với SUBSTRING.

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

12
Mặc dù tôi đồng ý rằng việc định dạng nói chung sẽ xảy ra ở nơi khác, tất cả chúng ta đều coi các chức năng định dạng ngày là đương nhiên. Chèn dấu phẩy có thể được thực hiện như hiển thị ở đây. +1.
EBarr

4
Tuy nhiên, điều này không hoạt động đối với các kiểu định dạng mony khác. Ở Thụy Sĩ, chúng tôi viết Tiền chẳng hạn dưới dạng này: 987'654'321.00 Làm thế nào để làm điều đó?
Daniel

6
Bạn có thể thực hiện thay thế CHỌN THAY THẾ (CHUYỂN ĐỔI (varchar, CAST (987654321 NHƯ tiền), 1), ',', '' '')
Hoody

4
Mặc dù tôi đồng ý rằng định dạng nên được thực hiện trong lớp trình bày nếu có thể, nhưng chắc chắn sẽ có những lúc, chẳng hạn như với cảnh báo Ignite / DPA, rằng email tôi nhận được là lớp trình bày. Cách duy nhất để đặt dấu phẩy ở một nơi như vậy là thông qua SQL. Có dấu phẩy với số lượng lớn là cực kỳ hữu ích trong những trường hợp đó.
PseudoToad

1
Mọi người đều muốn nói cho bạn biết "nên" làm gì, nhưng đó không phải là việc thiết kế mã của riêng bạn. Nếu mọi người chỉ làm những gì "nên" được thực hiện, thì chúng ta sẽ mất tinh thần sáng tạo và khả năng hack mọi thứ cùng nhau để giải quyết vấn đề nhanh chóng với sự phiền phức và nỗ lực tối thiểu.
Geoff Griswald

59

Tôi khuyên bạn nên Thay thế thay cho Chuỗi con để tránh các vấn đề về độ dài chuỗi:

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

3
Mặc dù việc chuyển đổi tiền không bao giờ thay đổi, tôi thích sự đảm bảo không vượt quá giới hạn mà Thay thế cung cấp qua Chuỗi con.
Sean

48

Đối với triển khai SQL Server 2012+, bạn sẽ có khả năng sử dụng FORMAT để áp dụng định dạng chuỗi cho các kiểu dữ liệu không phải chuỗi.

Trong câu hỏi ban đầu, người dùng đã yêu cầu khả năng sử dụng dấu phẩy dưới dạng hàng ngàn dấu phân cách. Trong một câu hỏi đóng như trùng lặp , người dùng đã hỏi làm thế nào họ có thể áp dụng định dạng tiền tệ. Các truy vấn sau đây cho thấy làm thế nào để thực hiện cả hai nhiệm vụ. Nó cũng cho thấy việc áp dụng văn hóa để biến điều này thành một giải pháp chung chung hơn (giải quyết chức năng của Tsiridis Dimitris để áp dụng định dạng đặc biệt của Hy Lạp)

-- 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 cho ở trên


1
Chia sẻ tuyệt vời, điều này sẽ có ích :)
jediC Ủy viên hội đồng

1
Fiddle bị hỏng, bây giờ nó nói String index out of range: 33
Jeff Puckett

1
@JeffPuckettII Vâng, thật đáng tiếc khi fiddle cho SQL Server không còn hoạt động. May mắn thay, bạn sẽ có thể dán phần trên vào bất kỳ công cụ truy vấn nào được kết nối với SQL Server 2012+
billinkc

20

Bản demo 1

Chứng minh thêm dấu phẩy:

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

Bản demo 2

Chứng minh dấu phẩy và dấu thập phân. Quan sát rằng nó làm tròn chữ số cuối cùng nếu cần thiết.

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

Khả năng tương thích

SQL Server 2012+.


2
Đây là một trong những! Hoạt động với len (cột) cũng như chỉ cột - trong khi một giải pháp 2012+ khác tôi đã thử.
Graham Laight

1
Tuyệt quá! Đây là câu trả lời tôi đang tìm kiếm (để sử dụng với T-SQL, kể cả trên SEDE )
ashleedawg

10

Vui lòng thử với truy vấn dưới đây:

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

Định dạng với dấu thập phân bên phải:

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

3
Vâng, đúng cách bây giờ chúng ta có FORMATchức năng SELECT format(123456789987654321,'###,##0'), hoặc đơn giản hơn, select format(123456789987654321, 'N0')như @ThomasMueller đã trả lời.
mattmc3

FORMAT là một cơn ác mộng về hiệu suất - bạn bắt đầu sử dụng nó và phụ thuộc vào nó, sau đó thấy rằng cơ sở dữ liệu của bạn không thể mở rộng quy mô. Và bây giờ nó được tích hợp vào hàng tá tính năng và bạn không thể thoát khỏi nó. Không bao giờ sử dụng FORMAT.
Pxtl

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

sản lượng = 9,876,543

và bạn có thể thay thế 9876543 bằng tên cột của bạn.


7

Đã thử mẹo lừa tiền ở trên và cách này hiệu quả với các giá trị số có hai hoặc ít hơn các chữ số có nghĩa. Tôi đã tạo chức năng của riêng mình để định dạng số với số thập phân:

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

Điều này thuộc về một bình luận cho câu trả lời của Phil Hunt nhưng than ôi tôi không có đại diện.

Để loại bỏ "0,00" khỏi cuối chuỗi số của bạn, tên phân tích là siêu tiện dụng. Nó mã hóa các chuỗi được phân tách bằng dấu chấm và trả về phần tử đã chỉ định, bắt đầu bằng mã thông báo ngoài cùng bên phải là phần tử 1.

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

Sản lượng "987,654,321"


3

đây là một UDF t-sql khác

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

Đây là một hàm vô hướng mà tôi đang sử dụng để sửa một số lỗi trong ví dụ trước (ở trên) và cũng xử lý các giá trị thập phân (với số chữ số được chỉ định) (EDITED cũng hoạt động với 0 & số âm). Một lưu ý khác, phương pháp đúc như tiền ở trên được giới hạn ở kích thước của loại dữ liệu TIỀN và không hoạt động với 4 (hoặc nhiều hơn) số thập phân. Phương pháp đó chắc chắn đơn giản hơn nhưng kém linh hoạt.

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

Một UDF khác hy vọng đủ chung chung và không đưa ra các giả định về việc bạn có muốn làm tròn đến một số vị trí thập phân cụ thể hay không:

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

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

. Số nguyên và vị trí thập phân bạn muốn hiển thị cho Số bạn chuyển qua làm đối số đầu vào. * /


0

Đối với SQL Server trước năm 2012 không bao gồm chức năng FORMAT, hãy tạo chức năng này:

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 

chọn dbo.FormatCurrency (12345678) trả về $ 12,345,678.00

Bỏ $ nếu bạn chỉ muốn dấu phẩy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.