SQL Server T-SQL LPAD & RPAD Functions (String Padding Equivalent to PadLeft & PadRight)

T-SQL 語法,是用來產生固定長度前面補零的數字字串

By Daniel Read

Submitted Thu, 2006-01-05 14:31

Here is my method for achieving left and right string padding in the Microsoft SQL Server T-SQL language. Unfortunately T-SQL does not offer functions like Oracle PL/SQL's LPAD() and RPAD() and C#'s PadLeft() and PadRight() functions. However, you can achieve the same thing using the T-SQL REPLICATE and LEN functions. Suppose you have a numeric column called Quantity and you need to return it as a string left-padded with 0's to exactly ten characters. You could do it this way:

SELECT REPLICATE('0', (10 - LEN(CAST(Quantity, VARCHAR)))) + CAST(Quantity, VARCHAR) AS PaddedQuantity
 FROM TableX

The calls to the CAST function are based on the assumption that the value you padding is numeric. If Quantity were already an string you could do it like this:

SELECT REPLICATE('0', (10 - LEN(Quantity))) + Quantity AS PaddedQuantity
 FROM TableX

In certain cases you might be concerned that that value you want to pad might be wider than your maximum number of characters. In that case you could use a CASE block to check the LEN of your input value to avoid passing a negative result to the second argument of the REPLICATE function. No need to worry about passing a 0 to REPLICATE, though: it will simply return an empty string, which is what you'd want since no padding would be necessary.

Update: I decided to go ahead and turn these into user defined functions. Here is a script for fnPadLeft:

IF EXISTS (
       SELECT *
       FROM dbo.sysobjects
      WHERE id = object_id(N'[dbo].[fnPadLeft]')
        AND xtype IN (N'FN', N'IF', N'TF')
      )
 DROP FUNCTION [dbo].[fnPadLeft]
GO

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO

CREATE FUNCTION fnPadLeft
(
 @PadChar char(1),
 @PadToLen int,
 @BaseString varchar(100)
)
RETURNS varchar(1000)
AS
/* ****************************************************
 Author:       Daniel Read

 Description:   
    Pads @BaseString to an exact length (@PadToLen) using the
    specified character (@PadChar). Base string will not be
    trimmed. Implicit type conversion should allow caller to
    pass a numeric T-SQL value for @BaseString.
   
    Unfortunately T-SQL string variables must be declared with an
    explicit width, so I chose 100 for the base and 1000 for the
    return. Feel free to adjust data types to suit your needs.
    Keep in mind that if you don't assign an explicit width to
    varchar it is the same as declaring varchar(1).
 
 Revision History:

 Date    Name Description
 ----    ---- -----------

***************************************************** */
BEGIN
 DECLARE @Padded varchar(1000)
 DECLARE @BaseLen int
 
 SET @BaseLen = LEN(@BaseString)
 
 IF @BaseLen >= @PadToLen
    BEGIN
      SET @Padded = @BaseString
    END
 ELSE
    BEGIN
      SET @Padded = REPLICATE(@PadChar, @PadToLen - @BaseLen) + @BaseString
   END 

 RETURN @Padded
END

GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

And for fnPadRight:

IF EXISTS (
       SELECT *
       FROM dbo.sysobjects
      WHERE id = object_id(N'[dbo].[fnPadRight]')
        AND xtype IN (N'FN', N'IF', N'TF')
      )
 DROP FUNCTION [dbo].[fnPadRight]
GO

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO

CREATE FUNCTION fnPadRight
(
 @PadChar char(1),
 @PadToLen int,
 @BaseString varchar(100)
)
RETURNS varchar(1000)
AS
/* ****************************************************
 Author:       Daniel Read

 Description:
    Pads @BaseString to an exact length (@PadToLen) using the
    specified character (@PadChar). Base string will not be
    trimmed. Implicit type conversion should allow caller to
    pass a numeric T-SQL value for @BaseString.
   
    Unfortunately T-SQL string variables must be declared with an
    explicit width, so I chose 100 for the base and 1000 for the
    return. Feel free to adjust data types to suit your needs.
    Keep in mind that if you don't assign an explicit width to
    varchar it is the same as declaring varchar(1).
 
 Revision History:

 Date    Name Description
 ----    ---- -----------

**************************************************** */
BEGIN
 DECLARE @Padded varchar(1000)
 DECLARE @BaseLen int
 
 SET @BaseLen = LEN(@BaseString)
 
 IF @BaseLen >= @PadToLen
    BEGIN
      SET @Padded = @BaseString
    END
 ELSE
    BEGIN
      SET @Padded = @BaseString + REPLICATE(@PadChar, @PadToLen - @BaseLen)
    END 

 RETURN @Padded
END

GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

Example usage:

SELECT dbo.fnPadLeft('X', 15, 100.25)
SELECT dbo.fnPadRight('X', 15, 'ABC')

 

 --------------------------------------------------------------------

今天看到一則 T-SQL 語法,是用來產生固定長度前面補零的數字字串,例如你拿到一個數值為 123 而你要將其數字轉成 00000123 的字串格式,我剛看到這個語法突然楞了一下,因為看到一個我沒用過的 POWER 函式,我看到這串 T-SQL 後突然聞到一點點怪怪的味道,因此寫出了幾個不同的版本,各位可以參考參考。


以下是我今天看到的寫法:


先將算出 10 的 8 次方 ( 10^8 )

然後加上原本的數字 @Number

將運算的結果(float)轉型成 varchar(9) 字串

最後從右邊算起取 8 個字元

針對效能的判斷:


因為 POWER 函式把原本 int 數字型別轉型為 float 型別,較佔記憶體空間

數字轉型 2 次 ( int –> float , float –> varchar )

字串函式處理 1 次

DECLARE @Number INT = 123


DECLARE @Digits INT = 8


DECLARE @Result CHAR(8)


-- 第一種


SELECT @Result =

    RIGHT(

        CAST(

            POWER(10, @Digits) + @Number

            AS VARCHAR(9))

        , @Digits)



SELECT @Result

---


好奇的我我自己重寫如下:


將原本的數字 @Number 轉型成 varchar(8) 後算出資料的長度 ( 注意:不能用 nvarchar 喔!! )

再用 REPLICATE 函式產生特定數量的 '0'

最後再加上原本的數字 @Number 轉型成 varchar(8) 後的字串

針對效能的判斷:


數字轉型 2 次 ( int –> varchar )0; → 若多新增一組變數可省去 1 次數值轉型的負擔

數值函式處理 1 次 ( DATALENGTH )

字串函式處理 1 次 ( REPLICATE )

字串相加 1 次

DECLARE @Number INT = 123


DECLARE @Digits INT = 8


DECLARE @Result CHAR(8)


-- 第二種


SELECT @Result =

REPLICATE('0', 

@Digits - DATALENGTH(CAST(@Number AS VARCHAR(8)))) +

CAST(@Number as VARCHAR(8))

SELECT @Result

---


最後我到噗浪上詢問網友的看法,果然由 Sean 提供了一個更直覺的寫法:


用 REPLICATE 函式產生固定位數 (@Digits) 的 '0'

將 @Number 轉型成 varchar 字串 (不指定長度)

最後從右邊算起取 8 個字元

針對效能的判斷:


數字轉型 1 次 ( int –> varchar )

字串函式處理 2 次 ( REPLICATE + RIGHT )

字串相加 1 次

DECLARE @Number INT = 123


DECLARE @Digits INT = 8


DECLARE @Result CHAR(8)


-- 第三種


SELECT @Result =

RIGHT(

REPLICATE('0', @Digits) + CAST(@Number as VARCHAR)

, @Digits)


SELECT @Result

---


我不敢說以上三種寫法哪個是好、哪個是壞,在效能上應該不會差多少,畢竟這並非頻繁執行的 T-SQL 語法,但如果以「可讀性」來看,我應該會選擇第三種寫法。


除此之外,網路上也有人(Daniel Read)提供一個寫好的 Function 可供使用,感覺也不錯,當 Function 建立好之後,只要輸入以下 T-SQL 就可以完成使命,可讀性超高! ^_^


SELECT dbo.fnPadLeft('0', 8, 123)

0; 

posted on 2010-11-19 09:59  巍巍边疆  阅读(896)  评论(0编辑  收藏  举报