SQL Server 2008'de 3 karakter uzunluğunda olacak şekilde bir dizeyi sıfırlarla doldurun


398

SQL Server 2008 R2'de ilk oluşturulduğunda 3 karakter uzunluğunda bir dize var.

Önde gelen sıfırlarla doldurmak istiyorum, eğer orijinal değeri '1' olsaydı yeni değer '001' olurdu. Veya orijinal değeri '23' ise, yeni değer '023'tür. Veya orijinal değeri '124' ise, yeni değer orijinal değerle aynıdır.

SQL Server 2008 R2 kullanıyorum. Bunu T-SQL kullanarak nasıl yapabilirim?



Yanıtlar:


681

Alan zaten bir dize ise, bu çalışır

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

Boş değerlerin '000' olarak gösterilmesini istiyorsanız

Bir tamsayı olabilir - o zaman istersiniz

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

Sorunun gerektirdiği gibi bu cevap sadece uzunluk <= 3 ise işe yarar, daha büyük bir şey istiyorsanız dize sabitini ve iki tamsayı sabitini gereken genişliğe değiştirmeniz gerekir. Örneğin'0000' and VARCHAR(4)),4


8
Ben sadece 2-3 karakter uzunluğunda bir avuç değer vardı bir Char (6) alan vardı ve yukarıdaki benim için işe yaramadı. Çalışması için '000000' + ISNULL (FIELD, '') etrafına bir RTRIM eklemek zorunda kaldım.
DWiener

3
Hogan evet anladım, ama ipin ne kadar uzun sürmediği önemli değil, nedenini anlamak için biraz meşgulüm ama bunun özü CHAR (6) alanımın sadece SAĞ ('000000 '+ ISNULL (alan,' '), 6) işe yaramadı, ancak SAĞ (' 000000 '+ ISNULL (alan,' ')), 6) işe yaradı.
DWiener

2
oh anlıyorum, dize olarak kodlanmış bir sayının sağında boşluklar vardı.
Hogan

3
@dwiener bir karakter sabit uzunluklu bir veri türü olduğu için bu davranışı elde edersiniz, bu nedenle durumunuzda karakter (6) 6 karakter uzunluğundadır. Gerçek değeriniz 6'dan küçükse, sağdaki boşluklarla doldurulur, böylece önerilen cevap bir karakter için doğru sonuç verir (6).
Giannis Paraskevopoulos

2
@Hogan, evet, ama bu soru "sql eklemek önde gelen sıfırlar" için top1 google sonucu, bu yüzden diğer veritabanlarında bilmek için birçok kişi (sqlserver kullanmayın, ancak google bu) yararlı olacağını düşünüyorum daha convient fonksiyonu var lpad. Yine de teşekkürler.
diralik

142

Her ne kadar soru SQL Server 2008 R2 için olsa da, birinin 2012 ve üzeri sürümlerle okuması durumunda, o zamandan beri FORMAT kullanımı ile çok daha kolay hale geldi .

Biçim bağımsız değişkeni olarak standart bir sayısal biçim dizesi veya özel bir sayısal biçim dizesi iletebilirsiniz ( bu ipucu için Vadim Ovchinnikov'a teşekkür edin ).

Bu soru için, örneğin,

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

çıktılar

001
001

2
Giriş numarası 111 veya 11 ise ne olur?
Hogan

6
1 için 001, 11 için 011 ve 111 için 111
Géza

2
'00 # 'yerine' D3 'kullanabilirsiniz.
Vadim Ovchinnikov

1
kabul edilen cevaptan oldukça yavaş görünüyor, ancak büyük miktarda veriyle çalışmazsa sooo çok daha kolay
kök

2
Mantıksız görünse de, FORMAT'ın varchar ile değil yalnızca sayısal ve tarih türleriyle çalıştığını belirtmek gerekir.
strattonn

120

Güvenli yöntem:

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

Bunun avantajı, '***'sınır dışı girdinin güzel ve açık bir göstergesi olan n <0 veya n> 999 için dizeyi döndürme avantajına sahiptir . Burada listelenen diğer yöntemler, girişi 3 karakterlik bir alt dizeye kısaltarak sessizce başarısız olacaktır.


10
Kahretsin, bu sayfaya kim inerse bu zirveye çıkmalı!
MarioDS

1
Bu yöntemle dikkatli olun. İfade belirtilen uzunluğu aştığında, dize belirtilen uzunluk için ** değerini döndürür. örneğin str (n, 10) için n = 1000000000 olduğunda yıldızlar (*) belirir.
Unbound

Bunun nasıl çalıştığını bilmiyorum ama şaşırtıcı ve basit.
RaRdEvA

1
Buna dikkat edin, dizeler onu kırdı (ve OP "bir dizeyi doldurmak" istedi). Çalışır: SELECT REPLACE(STR('1',3),' ','0')Aralar: SELECT REPLACE(STR('1A',3),' ','0'). Bir kullanıcı giriş dizesine bir harf girdiğinde bugün beni yaktı ve bu durumu test edemedim.
Jeff Mergler

@Ubound Bu şekilde çalışmak niyetinde, poster zaten söylüyor. Diğer tekliflerin yaptığı gibi kesilmiş bir değerden *** daha iyi dönmek, parametrelerin yanlış olduğunu gösterir.
Marc Guillot

32

İstenen genişliğe kadar sol dolgu için daha genel bir teknik:

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)

Ancak, negatif değerlerle uğraşıyorsanız ve baştaki sıfırlarla dolduruyorsanız, ne bu ne de önerilen diğer teknikler işe yaramaz. Şuna benzeyen bir şey alırsınız:

00-123

[Muhtemelen istediğin gibi değil]

Yani… bazı ek çemberlerden atlamanız gerekecek İşte negatif sayıları doğru şekilde biçimlendirecek bir yaklaşı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
         )

Bir unutmamalıdır convert()çağrıları belirtmelidir [n]varcharkesikleri ile dönüştürülmüş sonucu tutan yeterli uzunlukta.


2
@StenPetrov, Teşekkürler. Her şey neyi başarmaya çalıştığınıza bağlıdır. Büyük, gerçek dünyadaki üretim veritabanlarında güvenmeyi öğrendiğim tek şey, şu ya da bu türden kötü verilerin varlığıdır. Ve eğer yapabilirsem
Nicholas Carey

:) yine de bu 3AM çağrısı geldiğinde ben çok 10 karmaşık olanlardan 1 basit satır okumak zorunda. Değişkenlerin eklenmesi, özellikle başka bir ekip üyesi bunları anında hesaplamaya karar verdiğinde ve negatif olmayan @ genişliğini kontrol etmediyse, işleri daha da kötüleştirir ...
Sten Petrov

Bu eklenen değişkenler sadece genelleme içindir - değerleri kodlayabilirsiniz. Bir astar için bir skaler fonksiyon oluşturabilirsiniz - o zaman bir astarınız vardır.
Gerard ONeill

30

İşte SQL Server Express 2012'de kullandığım Hogan'ın cevabının bir çeşidi:

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

Alan bir dize olup olmadığını endişe yerine, ben sadece CONCAT, çünkü zaten bir dize çıktı olacak. Ayrıca, alan bir olabilirse NULL, ISNULLişlevin NULLsonuç almasını önlemek için kullanmak gerekebilir .

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

1
Hatırladığım kadarıyla CONCAT null ise değeri yok sayar, bu yüzden birincisi iyi çalışır.
Marie

Bu çözüm, Field
Unbound

23

Her zaman aşağıdaki yöntemi çok yararlı buldum.

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

15

Her duruma uygun bu işlevi kullanın.

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

Örnek çıktı

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 

Sayılar ve karakter dizileri üzerinde çalıştığı için kabul edilen cevap bu olmalıdır . Ve bir işlev kullanmak istemiyorsanız (ama neden olmasın) böyle bir şey de işe yarar: DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 12 - LEN(@NumStr)) + @NumStr;Salar'ın yukarıdaki ilk örneğini döndürür. Teşekkürler Salar.
Jeff Mergler

Yukarıdaki yorumumda bir yazım hatası vardı, bu yazılmalıdır: yukarıdaki ilk örnekte DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 10 - LEN(@NumStr)) + @NumStr;geri döner 0000002016.
Jeff Mergler

@JeffMergler - bu sayı ve karakter dizileri üzerinde nasıl çalışır? Bir tamsayı parametresi alan bir işlevdir. Soru dizelerle ilgiliydi.
Hogan

5

Mevcut verilerini güncellemek isteyenler için sorgu:

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

3

Tamsayılar için int'ten varchar'a örtük dönüşümü kullanabilirsiniz:

SELECT RIGHT(1000 + field, 3)

4
Ancak, bu yeterince büyük bir değer verildiğinde başarısız olur, ayrıca, negatif değerler için ... ilginç sonuçlar alırsınız.
Nicholas Carey

3

Eski biletini biliyorum, sadece paylaşmayı düşündüm.

Bu kodu bir çözüm arıyor buldum. MSSQL'in tüm sürümlerinde çalışıp çalışmadığından emin değilim MSSQL 2016 var.

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

"0023" değerini döndürür STR işlevindeki 4, değer dahil toplam uzunluktur. Örnek 4, 23 ve 123'ün tümü STR'de 4 olacak ve doğru miktarda sıfır eklenecektir. Artırabilir veya azaltabilirsiniz. 23 üzerinde uzunluk elde etmeye gerek yok.

Düzenleme: Ben @Anon yazı ile aynı görüyorum.


2

Sabit boyutlu varchar (veya dize) çıktı gerektiğinde girdi olarak tamsayı sütun ile benzer bir sorun vardı. Örneğin, 1 ila '01', 12 ila '12'. Bu kod çalışır:

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

Giriş de bir varchar sütunu ise, döküm parçasından kaçınabilirsiniz.


2

Daha dinamik bir yaklaşım için bunu deneyin.

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

2

Bunu sabit uzunlukta deneyin.

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

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

1

Bunu yazdım çünkü belirli bir uzunluğa kadar gereksinimlerim vardı (9). SADECE girişin doldurulması gerektiğinde solda @ pattern ile doldurur. Her zaman @ pattern'de tanımlanan uzunluğu döndürmelidir.

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 girişini döndürür


1

Basit bu

Sevmek:

DECLARE @DUENO BIGINT
SET @DUENO=5

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

0

Burada özellikle SQL Server 2008'de tarihleri ​​DATETIMEOFFSET'e dönüştürmek için benim zaman dilimi dizgimi bir saat dilimi dizesine dönüştürmek için geldi. Brüt, ama gerekli.

Bu yüzden negatif ve pozitif sayılarla başa çıkacak 1 yönteme ihtiyacım var, gerekirse iki karakterle biçimlendiririz. Anons cevabı beni yakınlaştırdı, ancak negatif saat dilimi değerleri gerektiği gibi 0-5değil-05

Bu yüzden cevabını biraz değiştirerek, bu tüm saat dilimi dönüşümleri için işe yarıyor

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

Ben bigint ve bir önde gelen sıfır veya diğer tek karakter (max 20 karakter döndürüldü) hitap ve giriş numarası uzunluğundan daha az sonuçların uzunluğu sağlayan bu işlevi yarattı:

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,' ')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.