Tạo chuỗi có các số 0 đứng đầu để có 3 ký tự trong SQL Server 2008


398

Tôi có một chuỗi dài tối đa 3 ký tự khi lần đầu tiên được tạo trong SQL Server 2008 R2.

Tôi muốn đệm nó với các số 0 đứng đầu, vì vậy nếu giá trị ban đầu của nó là '1' thì giá trị mới sẽ là '001'. Hoặc nếu giá trị ban đầu của nó là '23' thì giá trị mới là '023'. Hoặc nếu giá trị ban đầu của nó là '124' thì giá trị mới giống với giá trị ban đầu.

Tôi đang sử dụng SQL Server 2008 R2. Làm thế nào tôi có thể làm điều này bằng cách sử dụng T-SQL?



Câu trả lời:


681

Nếu trường đã là một chuỗi, điều này sẽ hoạt động

 SELECT RIGHT('000'+ISNULL(field,''),3)

Nếu bạn muốn null hiển thị là '000'

Nó có thể là một số nguyên - sau đó bạn sẽ muốn

 SELECT RIGHT('000'+CAST(field AS VARCHAR(3)),3)

Theo yêu cầu của câu hỏi, câu trả lời này chỉ hoạt động nếu độ dài <= 3, nếu bạn muốn một cái gì đó lớn hơn, bạn cần thay đổi hằng chuỗi và hai hằng số nguyên thành chiều rộng cần thiết. ví dụ'0000' and VARCHAR(4)),4


8
Tôi đã có một trường Char (6) có một số giá trị chỉ dài 2-3 ký tự và những thứ trên không phù hợp với tôi. Tôi đã phải thêm RTRIM xung quanh '000000' + ISNULL (FIELD, '') để nó hoạt động.
DWiener

3
Hogan vâng tôi đã hiểu điều đó, nhưng cho dù chuỗi đó không hoạt động được bao lâu, tôi hơi bận rộn để tìm hiểu lý do tại sao nhưng ý chính của nó là với trường CHAR (6) của tôi chỉ thực hiện RIGHT ('000000 '+ ISNULL (trường,' '), 6) không hoạt động nhưng RIGHT (RTRIM (' 000000 '+ ISNULL (trường,' ')), 6) đã làm.
DWiener

2
oh tôi hiểu, bạn có khoảng trắng ở bên phải của một số được mã hóa dưới dạng chuỗi.
Hogan

3
@dwiener bạn có hành vi này vì char là kiểu dữ liệu có độ dài cố định, vì vậy trong trường hợp của bạn char (6) có nghĩa là 6 ký tự dài. Nếu giá trị thực tế của bạn nhỏ hơn 6, nó được đệm bằng các khoảng trống ở bên phải để câu trả lời được đề xuất sẽ tạo ra kết quả tổng hợp cho một char (6).
Giannis Paraskevopoulos

2
@Hogan, vâng, nhưng câu hỏi này là top1 kết quả google cho "sql add zeros hàng đầu", vì vậy tôi nghĩ rằng nó sẽ hữu ích cho nhiều người (những người không sử dụng sqlserver, nhưng google câu hỏi này) để biết rằng trong các cơ sở dữ liệu khác có thể tồn tại nhiều chức năng lpad. Dù sao cũng cảm ơn bạn.
diralik

142

Mặc dù câu hỏi dành cho SQL Server 2008 R2, nhưng trong trường hợp ai đó đang đọc bài này với phiên bản 2012 trở lên, thì từ đó việc sử dụng FORMAT trở nên dễ dàng hơn nhiều .

Bạn có thể chuyển một chuỗi định dạng số tiêu chuẩn hoặc một chuỗi định dạng số tùy chỉnh làm đối số định dạng (cảm ơn Vadim Ovchinnikov cho gợi ý này).

Đối với câu hỏi này, ví dụ như một mã như

DECLARE @myInt INT = 1;
-- One way using a standard numeric format string
PRINT FORMAT(@myInt,'D3');
-- Other way using a custom numeric format string
PRINT FORMAT(@myInt,'00#');

đầu ra

001
001

2
Điều gì xảy ra nếu số đầu vào là 111 hoặc 11?
Hogan

6
Đối với 1 là 001, đối với 11 là 011 và đối với 111 là 111
Géza

2
Bạn có thể sử dụng 'D3' thay vì '00 # '.
Vadim Ovchinnikov

1
nó dường như chậm hơn đáng kể so với câu trả lời được chấp nhận nhưng thật dễ dàng hơn nhiều nếu không làm việc với số lượng lớn dữ liệu
root

2
Mặc dù có vẻ phi logic, nhưng đáng chú ý là FORMAT chỉ hoạt động với các loại số và ngày, không phải varchar.
strattonn

120

Phương pháp an toàn:

SELECT REPLACE(STR(n,3),' ','0')

Điều này có lợi thế là trả về chuỗi '***'cho n <0 hoặc n> 999, đây là một chỉ báo đẹp và rõ ràng về đầu vào ngoài giới hạn. Các phương thức khác được liệt kê ở đây sẽ thất bại âm thầm bằng cách cắt đầu vào thành chuỗi con 3 ký tự.


10
Chết tiệt, bất cứ ai hạ cánh trên trang này sẽ giúp điều này nổi lên hàng đầu!
MarioDS

1
Trở nên tuyệt vời với phương pháp này. Khi biểu thức vượt quá độ dài đã chỉ định, chuỗi trả về ** cho độ dài đã chỉ định. ví dụ: str (n, 10), khi n = 1000000000 thì bạn sẽ xuất hiện các ngôi sao (*).
Không giới hạn

Tôi không biết làm thế nào điều này hoạt động nhưng là tuyệt vời và đơn giản.
RaRdEvA

1
Cẩn thận với cái này, các chuỗi phá vỡ nó (và OP đã yêu cầu "đệm một chuỗi"). Tác phẩm: SELECT REPLACE(STR('1',3),' ','0')Nghỉ : SELECT REPLACE(STR('1A',3),' ','0'). Điều này chỉ đốt cháy tôi hôm nay khi một người dùng nhập một chữ cái trong chuỗi đầu vào và tôi đã không kiểm tra trường hợp đó.
Jeff Mergler

@ Unbound Đây là cách nó dự định hoạt động, người đăng đã nói nó. Tốt hơn là trả về *** hơn là một giá trị bị cắt bớt như tất cả các đề xuất khác, điều đó cho thấy các tham số đã sai.
Marc Guillot

32

Đây là một kỹ thuật tổng quát hơn cho phần đệm bên trái với bất kỳ chiều rộng mong muốn nào:

declare @x     int     = 123 -- value to be padded
declare @width int     = 25  -- desired width
declare @pad   char(1) = '0' -- pad character

select right_justified = replicate(
                           @pad ,
                           @width-len(convert(varchar(100),@x))
                           )
                       + convert(varchar(100),@x)

Tuy nhiên, nếu bạn đang xử lý các giá trị âm và đệm với các số 0 đứng đầu, thì điều này cũng như các kỹ thuật được đề xuất khác sẽ không hoạt động. Bạn sẽ nhận được một cái gì đó trông như thế này:

00-123

[Có lẽ không phải là những gì bạn muốn]

Vì vậy, bạn sẽ phải vượt qua một số vòng bổ sung Đây là một cách tiếp cận sẽ định dạng đúng các số âm:

declare @x     float   = -1.234
declare @width int     = 20
declare @pad   char(1) = '0'

select right_justified = stuff(
         convert(varchar(99),@x) ,                            -- source string (converted from numeric value)
         case when @x < 0 then 2 else 1 end ,                 -- insert position
         0 ,                                                  -- count of characters to remove from source string
         replicate(@pad,@width-len(convert(varchar(99),@x)) ) -- text to be inserted
         )

Người ta cần lưu ý rằng các convert()cuộc gọi nên chỉ định một [n]varcharđộ dài đủ để giữ kết quả được chuyển đổi với cắt ngắn.


2
@StenPetrov, Cảm ơn bạn. Tất cả phụ thuộc vào những gì bạn đang cố gắng thực hiện. Một điều tôi đã học được để phụ thuộc vào các cơ sở dữ liệu sản xuất lớn trong thế giới thực là sự hiện diện của dữ liệu xấu loại này hay loại khác. Và tôi thích tránh các cuộc gọi điện thoại vào 3 giờ sáng nếu có thể; ^)
Nicholas Carey

:) khi cuộc gọi 3AM đó đến, tôi muốn đọc 1 dòng đơn giản hơn 10 dòng phức tạp. Việc thêm các biến càng khiến mọi thứ trở nên tồi tệ hơn, đặc biệt là nếu một thành viên khác trong nhóm quyết định tính toán chúng một cách nhanh chóng và không kiểm tra xem băng thông không âm ...
Sten Petrov

Các biến được thêm vào chỉ để khái quát hóa - bạn có thể mã cứng các giá trị. Đối với một lớp lót, bạn có thể tạo một hàm vô hướng - sau đó bạn có một lớp lót của mình.
Gerard ONeill

30

Đây là một biến thể của câu trả lời của Hogan mà tôi sử dụng trong SQL Server Express 2012:

SELECT RIGHT(CONCAT('000', field), 3)

Thay vì lo lắng liệu trường có phải là một chuỗi hay không, tôi chỉ là CONCATnó, vì dù sao nó cũng sẽ tạo ra một chuỗi. Ngoài ra, nếu trường có thể là một NULL, sử dụng ISNULLcó thể được yêu cầu để tránh chức năng nhận NULLkết quả.

SELECT RIGHT(CONCAT('000', ISNULL(field,'')), 3)

1
Theo tôi nhớ CONCAT chỉ bỏ qua giá trị nếu nó là null nên cái đầu tiên hoạt động tốt.
Marie

Giải pháp này sẽ hoạt động bất kể len ​​của Trường
Không giới hạn

23

Tôi luôn luôn tìm thấy phương pháp sau đây rất hữu ích.

REPLICATE('0', 5 - LEN(Job.Number)) + CAST(Job.Number AS varchar) as 'NumberFull'

15

Sử dụng chức năng này phù hợp với mọi tình huống.

CREATE FUNCTION dbo.fnNumPadLeft (@input INT, @pad tinyint)
RETURNS VARCHAR(250)
AS BEGIN
    DECLARE @NumStr VARCHAR(250)

    SET @NumStr = LTRIM(@input)

    IF(@pad > LEN(@NumStr))
        SET @NumStr = REPLICATE('0', @Pad - LEN(@NumStr)) + @NumStr;

    RETURN @NumStr;
END

Sản lượng mẫu

SELECT [dbo].[fnNumPadLeft] (2016,10) -- returns 0000002016
SELECT [dbo].[fnNumPadLeft] (2016,5) -- returns 02016
SELECT [dbo].[fnNumPadLeft] (2016,2) -- returns 2016
SELECT [dbo].[fnNumPadLeft] (2016,0) -- returns 2016 

Đây phải là câu trả lời được chấp nhận vì nó hoạt động trên các số và chuỗi . Và nếu bạn không muốn sử dụng một chức năng (nhưng tại sao không) thì một cái gì đó như thế này cũng hoạt động: DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 12 - LEN(@NumStr)) + @NumStr;trả về ví dụ đầu tiên của Salar ở trên. Cảm ơn Salar.
Jeff Mergler

Nhận xét của tôi ở trên có một lỗi đánh máy, nó nên đọc: DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 10 - LEN(@NumStr)) + @NumStr;trả về 0000002016trong ví dụ đầu tiên ở trên.
Jeff Mergler

@JeffMergler - Làm thế nào để nó hoạt động trên các số và chuỗi? Đây là một hàm có một tham số nguyên. Câu hỏi là về chuỗi.
Hogan

5

Đối với những người muốn cập nhật dữ liệu hiện có của họ ở đây là truy vấn:

update SomeEventTable set eventTime=RIGHT('00000'+ISNULL(eventTime, ''),5)

3

Đối với số nguyên, bạn có thể sử dụng chuyển đổi ngầm định từ int sang varchar:

SELECT RIGHT(1000 + field, 3)

4
Tuy nhiên, điều đó sẽ thất bại với một giá trị đủ lớn, hơn nữa, đối với các giá trị âm, bạn sẽ nhận được ... kết quả thú vị.
Nicholas Carey

3

Tôi biết vé cũ của nó tôi chỉ nghĩ để chia sẻ nó.

Tôi tìm thấy mã này tìm kiếm một giải pháp. Không chắc chắn nếu nó hoạt động trên tất cả các phiên bản MSSQL, tôi có MSSQL 2016.

declare @value as nvarchar(50) = 23
select REPLACE(STR(CAST(@value AS INT) + 1,4), SPACE(1), '0') as Leadingzero

trả về "0023" Số 4 trong hàm STR là tổng chiều dài bao gồm cả giá trị. Ví dụ 4, 23 và 123 tất cả sẽ có 4 trong STR và số lượng không chính xác sẽ được thêm vào. Bạn có thể tăng hoặc giảm nó. Không cần phải lấy chiều dài trên 23.

Chỉnh sửa: Tôi thấy nó giống như bài đăng @Anon.


3

Hãy thử điều này với chiều dài cố định.

select right('000000'+'123',5)

select REPLICATE('0', 5 - LEN(123)) + '123'

2

Tôi gặp vấn đề tương tự với cột số nguyên làm đầu vào khi tôi cần đầu ra varchar (hoặc chuỗi) có kích thước cố định. Chẳng hạn, 1 đến '01', 12 đến '12'. Mã này hoạt động:

SELECT RIGHT(CONCAT('00',field::text),2)

Nếu đầu vào cũng là một cột của varchar, bạn có thể tránh phần đúc.


2

Đối với một cách tiếp cận năng động hơn hãy thử điều này.

declare @val varchar(5)
declare @maxSpaces int
set @maxSpaces = 3
set @val = '3'
select concat(REPLICATE('0',@maxSpaces-len(@val)),@val)

1

Đã viết điều này bởi vì tôi có yêu cầu cho một chiều dài cụ thể (9). Đệm bên trái với CHỈ @potype khi đầu vào cần đệm. Nên luôn trả về độ dài được xác định trong @potype.

declare @charInput as char(50) = 'input'

--always handle NULL :)
set @charInput = isnull(@charInput,'')

declare @actualLength as int = len(@charInput)

declare @pattern as char(50) = '123456789'
declare @prefLength as int = len(@pattern)

if @prefLength > @actualLength
    select Left(Left(@pattern, @prefLength-@actualLength) + @charInput, @prefLength)
else
    select @charInput

Trả về 1234


1

Đơn giản là

Giống:

DECLARE @DUENO BIGINT
SET @DUENO=5

SELECT 'ND'+STUFF('000000',6-LEN(RTRIM(@DueNo))+1,LEN(RTRIM(@DueNo)),RTRIM(@DueNo)) DUENO

0

Tôi đã đến đây một cách cụ thể để tìm hiểu làm thế nào tôi có thể chuyển đổi múi giờ của mình thành chuỗi múi giờ để chuyển đổi ngày thành DATETIMEOFFSET trong SQL Server 2008, nhưng cần thiết.

Vì vậy, tôi cần 1 phương thức sẽ đối phó với các số âm và dương, định dạng chúng thành hai ký tự có số 0 đứng đầu nếu cần. Câu trả lời của Anons đã khiến tôi gần gũi, nhưng các giá trị múi giờ âm sẽ xuất hiện 0-5thay vì bắt buộc-05

Vì vậy, với một chút điều chỉnh về câu trả lời của anh ấy, điều này hoạt động cho tất cả các chuyển đổi giờ múi giờ

DECLARE @n INT = 13 -- Works with -13, -5, 0, 5, etc
SELECT CASE 
    WHEN @n < 0 THEN '-' + REPLACE(STR(@n * -1 ,2),' ','0') 
    ELSE '+' + REPLACE(STR(@n,2),' ','0') END + ':00'

-1

Tôi đã tạo chức năng này phục vụ cho bigint và một số 0 hoặc một ký tự đơn khác (trả lại tối đa 20 ký tự) và cho phép độ dài kết quả nhỏ hơn độ dài của số đầu vào:

create FUNCTION fnPadNum (
  @Num BIGINT --Number to be padded, @sLen BIGINT --Total length of results , @PadChar varchar(1))
  RETURNS VARCHAR(20)
  AS
  --Pads bigint with leading 0's
            --Sample:  "select dbo.fnPadNum(201,5,'0')" returns "00201"
            --Sample:  "select dbo.fnPadNum(201,5,'*')" returns "**201"
            --Sample:  "select dbo.fnPadNum(201,5,' ')" returns "  201"
   BEGIN
     DECLARE @Results VARCHAR(20)
     SELECT @Results = CASE 
     WHEN @sLen >= len(ISNULL(@Num, 0))
     THEN replicate(@PadChar, @sLen - len(@Num)) + CAST(ISNULL(@Num, 0) AS VARCHAR)
     ELSE CAST(ISNULL(@Num, 0) AS VARCHAR)
     END

     RETURN @Results
     END
     GO

     --Usage:
      SELECT dbo.fnPadNum(201, 5,'0')
      SELECT dbo.fnPadNum(201, 5,'*')
      SELECT dbo.fnPadNum(201, 5,' ')
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.