วางสตริงที่มีศูนย์นำหน้าเพื่อให้มีความยาว 3 อักขระใน SQL Server 2008


398

ฉันมีสตริงที่ยาวไม่เกิน 3 อักขระเมื่อสร้างขึ้นครั้งแรกใน SQL Server 2008 R2

ฉันต้องการซับด้วยศูนย์นำหน้าดังนั้นถ้าค่าเดิมเป็น '1' ดังนั้นค่าใหม่จะเป็น '001' หรือถ้าค่าเดิมเป็น '23' ค่าใหม่คือ '023' หรือถ้าค่าเดิมเป็น '124' ค่าใหม่จะเหมือนกับค่าเดิม

ฉันใช้ SQL Server 2008 R2 ฉันจะทำสิ่งนี้โดยใช้ T-SQL ได้อย่างไร



คำตอบ:


681

ถ้าเขตข้อมูลเป็นสตริงอยู่แล้วสิ่งนี้จะทำงาน

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

หากคุณต้องการให้ค่า Null แสดงเป็น '000'

มันอาจจะเป็นจำนวนเต็ม - แล้วคุณจะต้องการ

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

ตามคำถามที่ต้องการคำตอบนี้ใช้ได้เฉพาะในกรณีที่ความยาว <= 3 ถ้าคุณต้องการบางสิ่งที่ใหญ่กว่าคุณต้องเปลี่ยนค่าคงที่สตริงและค่าคงที่จำนวนเต็มสองค่าเป็นความกว้างที่ต้องการ เช่น'0000' and VARCHAR(4)),4


8
ฉันมีช่อง Char (6) ที่มีค่าไม่กี่ตัวที่มีความยาวเพียง 2-3 ตัวอักษรและด้านบนไม่ได้ผลสำหรับฉัน ฉันต้องเพิ่ม RTRIM รอบ '000000' + ISNULL (FIELD, '') เพื่อให้มันใช้งานได้
DWiener

3
โฮแกนใช่ฉันได้รับมา แต่ไม่ว่ามันจะใช้งานได้นานแค่ไหนฉันก็ยุ่งเกินกว่าจะหาเหตุผลว่าทำไม แต่สิ่งที่สำคัญคือมันมีฟิลด์ CHAR (6) ของฉันเพิ่งทำขวา ('000000') '+ ISNULL (ฟิลด์,' '), 6) ไม่ทำงานยกเว้น RIGHT (RTRIM (' 000000 '+ ISNULL (ฟิลด์,' ')), 6)
DWiener

2
โอ้ฉันเข้าใจคุณมีช่องว่างทางด้านขวาของตัวเลขที่เข้ารหัสเป็นสตริง
โฮแกน

3
@dwiener คุณมีพฤติกรรมนี้เนื่องจากถ่านเป็นชนิดข้อมูลที่มีความยาวคงที่ดังนั้นในกรณีของคุณถ่าน (6) หมายถึงยาว 6 ตัวอักษร หากมูลค่าที่แท้จริงของคุณน้อยกว่า 6 มันจะถูกเติมด้วยช่องว่างทางด้านขวาดังนั้นคำตอบที่เสนอจะให้ผลลัพธ์ที่เป็นประโยชน์สำหรับ char (6)
Giannis Paraskevopoulos

2
@ โฮแกนใช่ แต่คำถามนี้เป็นผลลัพธ์ top1 ของ Google สำหรับ "sql เพิ่มศูนย์นำหน้า" ดังนั้นฉันคิดว่ามันจะเป็นประโยชน์สำหรับคนจำนวนมาก (ที่ไม่ได้ใช้ sqlserver แต่ google คำถามนี้) รู้ว่าในฐานข้อมูลอื่นอาจ มีฟังก์ชั่น Convient มากขึ้น lpad ขอบคุณ
diralik

142

แม้ว่าคำถามคือสำหรับ SQL Server 2008 R2 ในกรณีที่มีใครบางคนที่อ่านข้อความนี้กับรุ่นปี 2012 และข้างต้นตั้งแต่นั้นมาก็กลายเป็นเรื่องง่ายโดยใช้รูปแบบ

คุณสามารถส่งสตริงรูปแบบตัวเลขมาตรฐานหรือสตริงรูปแบบตัวเลขที่กำหนดเองเป็นอาร์กิวเมนต์รูปแบบ (ขอบคุณVadim Ovchinnikovสำหรับคำแนะนำนี้)

สำหรับคำถามนี้เช่นรหัสเช่น

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

เอาท์พุท

001
001

2
จะเกิดอะไรขึ้นถ้าหมายเลขอินพุตคือ 111 หรือ 11
โฮแกน

6
สำหรับ 1 คือ 001 สำหรับ 11 คือ 011 และสำหรับ 111 คือ 111
Géza

2
คุณสามารถใช้ 'D3' แทน '00 # '
Vadim Ovchinnikov

1
ดูเหมือนจะช้ากว่าคำตอบที่ยอมรับอย่างมาก แต่จะง่ายกว่ามากถ้าไม่ทำงานกับข้อมูลจำนวนมาก
root

2
แม้ว่ามันจะดูไร้เหตุผล แต่ก็น่าสังเกตว่า FORMAT ใช้ได้กับประเภทตัวเลขและวันที่เท่านั้นไม่ใช่ varchar
strattonn

120

วิธีที่ปลอดภัย:

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

นี่เป็นข้อดีของการคืนค่าสตริง'***'สำหรับ n <0 หรือ n> 999 ซึ่งเป็นตัวบ่งชี้ที่ดีและชัดเจนของอินพุตนอกขอบเขต วิธีอื่น ๆ ที่แสดงไว้ที่นี่จะล้มเหลวอย่างเงียบ ๆ โดยตัดทอนอินพุตให้กับสตริงย่อย 3 อักขระ


10
เจ้ากรรมใครก็ตามที่เข้ามาในหน้านี้จะช่วยลอยนี้ขึ้นไปข้างบน!
MarioDS

1
กลายเป็นด้วยวิธีนี้ เมื่อนิพจน์เกินความยาวที่ระบุสตริงจะส่งคืน ** สำหรับความยาวที่ระบุ สำหรับเช่น str (n, 10), เมื่อ n = 1000000000 คุณจะมีดาว (*) ปรากฏ
Unbound

ฉันไม่รู้ว่ามันใช้งานได้อย่างไร แต่มันวิเศษและเรียบง่าย
RaRdEvA

1
ระมัดระวังกับสิ่งนี้สตริงทำลายมัน (และ OP ขอ "padding a สตริง") การทำงาน: เที่ยวบิน:SELECT REPLACE(STR('1',3),' ','0') SELECT REPLACE(STR('1A',3),' ','0')สิ่งนี้เพิ่งจะเผาฉันในวันนี้เมื่อผู้ใช้ป้อนตัวอักษรในสตริงอินพุตและฉันไม่สามารถทดสอบเคสได้
Jeff Mergler

@Unbound นี่เป็นวิธีการทำงานโปสเตอร์มีการระบุไว้แล้ว ดีกว่าที่จะคืนค่า *** มากกว่าค่าที่ถูกตัดทอนเช่นเดียวกับข้อเสนออื่น ๆ ทั้งหมดแสดงว่าพารามิเตอร์ผิด
Marc Guillot

32

นี่เป็นเทคนิคทั่วไปสำหรับการเว้นระยะห่างจากซ้ายไปจนถึงความกว้างที่ต้องการ:

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)

อย่างไรก็ตามหากคุณกำลังจัดการกับค่าลบและการเติมด้วยเลขศูนย์นำหน้าไม่ว่าจะเป็นแบบนี้หรือเทคนิคอื่น ๆ ที่แนะนำจะใช้งานได้ คุณจะได้รับสิ่งที่มีลักษณะเช่นนี้:

00-123

[อาจไม่ใช่สิ่งที่คุณต้องการ]

ดังนั้น…คุณจะต้องข้ามห่วงเพิ่มเติมนี่คือวิธีหนึ่งที่จะจัดรูปแบบจำนวนลบได้อย่างถูกต้อง:

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
         )

หนึ่งควรทราบว่าการconvert()โทรควรระบุ[n]varcharความยาวเพียงพอที่จะเก็บผลการแปลงด้วยการตัดทอน


2
@StenPetrov ขอบคุณ ทุกอย่างขึ้นอยู่กับสิ่งที่คุณพยายามทำให้สำเร็จ สิ่งหนึ่งที่ฉันเรียนรู้ที่จะพึ่งพาฐานข้อมูลการผลิตขนาดใหญ่ในโลกแห่งความเป็นจริงคือการมีข้อมูลที่ไม่ดีในประเภทใดประเภทหนึ่ง และฉันชอบที่จะหลีกเลี่ยงการโทรศัพท์ 3:00 ถ้าฉันสามารถ; ^)
Nicholas Carey

:) ยังเมื่อโทร 3AM ที่มาในฉันค่อนข้างจะต้องอ่าน 1 บรรทัดง่ายกว่า 10 ซับซ้อน การเพิ่มตัวแปรเพิ่มเติมทำให้สิ่งเลวร้ายยิ่งขึ้นโดยเฉพาะอย่างยิ่งถ้าสมาชิกในทีมคนอื่นตัดสินใจที่จะคำนวณพวกเขาได้ทันทีและไม่ได้ตรวจสอบ @width ที่ไม่เป็นลบ ...
Sten Petrov

ตัวแปรที่เพิ่มเข้ามานั้นเป็นเพียงการวางนัยทั่วไป - คุณสามารถกำหนดรหัสค่าได้ยาก สำหรับหนึ่งซับคุณสามารถสร้างฟังก์ชั่นสเกลาร์ - จากนั้นคุณมีหนึ่งซับของคุณ
เจอราร์ดโอนีล

30

นี่คือคำตอบที่แตกต่างของโฮแกนที่ฉันใช้ใน SQL Server Express 2012:

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

แทนที่จะต้องกังวลว่าฟิลด์นั้นเป็นสตริงหรือไม่ฉันก็CONCATเลยเพราะมันจะส่งออกสตริงอยู่ดี นอกจากนี้ถ้าเขตข้อมูลสามารถ a NULL, ISNULLอาจจำเป็นต้องใช้เพื่อหลีกเลี่ยงการให้ฟังก์ชันรับNULLผลลัพธ์

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

1
เท่าที่ฉันจำ CONCAT เพียงละเว้นค่าหากเป็นโมฆะดังนั้นคนแรกทำงานได้ดี
มารี

การแก้ปัญหานี้จะทำงานโดยไม่คำนึงถึง len ของ Field
Unbound

23

ฉันพบวิธีต่อไปนี้เพื่อเป็นประโยชน์เสมอ

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

15

ใช้ฟังก์ชั่นนี้ที่เหมาะสมกับทุกสถานการณ์

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

ตัวอย่างผลลัพธ์

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 

นี้ควรจะเป็นคำตอบที่ได้รับการยอมรับเพราะการทำงานเกี่ยวกับตัวเลขและสตริง และถ้าคุณไม่ต้องการใช้ฟังก์ชั่น (แต่ทำไมไม่) บางอย่างเช่นนี้ก็ใช้งานได้DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 12 - LEN(@NumStr)) + @NumStr;ซึ่งส่งกลับตัวอย่างแรกของ Salar ด้านบน ขอบคุณ Salar
Jeff Mergler

ความคิดเห็นของฉันด้านบนมีคำที่พิมพ์ผิดคุณควรอ่าน: DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 10 - LEN(@NumStr)) + @NumStr;ผลตอบแทนใด0000002016ในตัวอย่างแรกข้างต้น
Jeff Mergler

@JeffMergler - ทำงานกับตัวเลขและสตริงได้อย่างไร มันเป็นฟังก์ชั่นที่ใช้พารามิเตอร์จำนวนเต็ม คำถามเกี่ยวกับสตริง
โฮแกน

5

สำหรับผู้ที่ต้องการอัปเดตข้อมูลที่มีอยู่ที่นี่เป็นคำถาม:

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

3

สำหรับจำนวนเต็มคุณสามารถใช้การแปลงโดยนัยจาก int ถึง varchar:

SELECT RIGHT(1000 + field, 3)

4
อย่างไรก็ตามนั่นจะล้มเหลวเนื่องจากมีค่ามากพอและยิ่งกว่านั้นสำหรับค่าลบคุณจะได้รับ ... ผลลัพธ์ที่น่าสนใจ
Nicholas Carey

3

ฉันรู้ว่าตั๋วเก่าของฉันฉันเพิ่งคิดที่จะแบ่งปัน

ฉันพบรหัสนี้เพื่อค้นหาวิธีแก้ไข ไม่แน่ใจว่าใช้ได้กับ MSSQL ทุกรุ่นหรือไม่ฉันมี MSSQL 2016

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

ส่งคืน "0023" 4 ในฟังก์ชัน STR คือความยาวทั้งหมดรวมถึงค่า ตัวอย่างที่ 4, 23 และ 123 ทั้งหมดจะมี 4 ใน STR และจำนวนศูนย์ที่ถูกต้องจะถูกเพิ่มเข้าไป คุณสามารถเพิ่มหรือลดได้ ไม่จำเป็นต้องมีความยาวในวันที่ 23

แก้ไข: ฉันเห็นข้อความเหมือนกับ @Anon โพสต์


2

ฉันมีปัญหาคล้ายกันกับคอลัมน์จำนวนเต็มเป็นอินพุตเมื่อฉันต้องการเอาต์พุต varchar (หรือสตริง) ขนาดคงที่ ตัวอย่างเช่น 1 ถึง '01', 12 ถึง '12' รหัสนี้ใช้งานได้:

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

หากอินพุตยังเป็นคอลัมน์ของ varchar คุณสามารถหลีกเลี่ยงส่วนที่หล่อได้


2

สำหรับวิธีการแบบไดนามิกมากขึ้นลองสิ่งนี้

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


1

เขียนสิ่งนี้เพราะฉันมีความต้องการไม่เกินความยาวที่กำหนด (9) วางแผ่นด้านซ้ายด้วย @pattern เท่านั้นเมื่ออินพุตต้องการการเติมเต็ม ควรส่งคืนความยาวที่กำหนดใน @ รูปแบบเสมอ

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

ส่งคืน 1234 อินพุต



0

ฉันมาที่นี่โดยเฉพาะเพื่อหาวิธีที่ฉันสามารถแปลง timezoneoffset เป็นสตริงเขตเวลาสำหรับการแปลงวันที่เป็น DATETIMEOFFSET ใน SQL Server 2008 ขั้นต้น แต่จำเป็น

ดังนั้นฉันต้องการ 1 วิธีที่จะรับมือกับจำนวนลบและบวกจัดรูปแบบพวกเขาเป็นสองตัวอักษรด้วยศูนย์นำถ้าจำเป็น คำตอบไม่ได้ทำให้ฉันเข้าใกล้ แต่ค่าเขตเวลาเชิงลบจะออกมา0-5มากกว่าที่จำเป็น-05

ดังนั้นด้วยการปรับแต่งเล็กน้อยในคำตอบของเขาสิ่งนี้ใช้ได้กับการแปลงชั่วโมงทุกช่วงเวลา

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

ฉันสร้างฟังก์ชั่นนี้ซึ่งเหมาะสำหรับ bigint และหนึ่งตัวอักษรนำศูนย์หรืออักขระเดี่ยวอื่น ๆ (สูงสุด 20 ตัวอักษรที่ส่งคืน) และอนุญาตให้ความยาวของผลลัพธ์น้อยกว่าความยาวของจำนวนอินพุต:

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,' ')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.