Wypełnij ciąg wiodącymi zerami, aby miał 3 znaki w SQL Server 2008

398

Mam ciąg, który ma do 3 znaków, gdy jest tworzony po raz pierwszy w SQL Server 2008 R2.

Chciałbym uzupełnić go wiodącymi zerami, więc jeśli jego oryginalna wartość to „1”, wówczas nowa wartość to „001”. Lub jeśli jego pierwotna wartość wynosiła „23”, nową wartością jest „023”. Lub jeśli jego pierwotna wartość to „124”, wówczas nowa wartość jest taka sama jak wartość oryginalna.

Używam SQL Server 2008 R2. Jak miałbym to zrobić za pomocą T-SQL?

Sunil
źródło

Odpowiedzi:

681

Jeśli pole jest już ciągiem, zadziała

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

Jeśli chcesz, aby wartości null były wyświetlane jako „000”

Może to być liczba całkowita - wtedy byś chciał

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

Jak wymaga tego pytanie, ta odpowiedź działa tylko wtedy, gdy długość <= 3, jeśli chcesz czegoś większego, musisz zmienić stałą łańcucha i dwie stałe liczb całkowitych na wymaganą szerokość. na przykład'0000' and VARCHAR(4)),4

Hogan
źródło
8
Miałem pole Char (6), które miało garść wartości, które miały tylko 2-3 znaki, a powyższe nie działało dla mnie. Musiałem dodać RTRIM wokół „000000” + ISNULL (FIELD, ”), aby zadziałało.
DWiener
3
Hogan tak, dostałem to, ale bez względu na to, jak długi sznur nie zadziałał, jestem trochę zbyt zajęty, aby dowiedzieć się, dlaczego, ale sedno jest takie, że moje pole CHAR (6) robi po prostu PRAWO („000000 „+ ISNULL (pole,”), 6) nie działało, ale działało PRAWO (RTRIM („000000” + ISNULL (pole, ”)), 6).
DWiener
2
och, rozumiem, miałeś spacje po prawej stronie liczby zakodowanej jako ciąg.
Hogan
3
@dwiener masz takie zachowanie, ponieważ char jest typem danych o stałej długości, więc w twoim przypadku char (6) oznacza 6 znaków. Jeśli twoja rzeczywista wartość jest mniejsza niż 6, jest ona uzupełniana spacjami po prawej stronie, więc proponowana odpowiedź wygeneruje niepoprawny wynik dla znaku char (6).
Giannis Paraskevopoulos
2
@Hogan, tak, ale to pytanie jest wynikiem top1 google dla „sql dodaj wiodące zera”, więc myślę, że przydałoby się wielu osobom (którzy nie używają sqlserver, ale google to pytanie) wiedzieć, że w innych bazach danych może istnieje bardziej wygodna funkcja lpad. Mimo wszystko dziekuję.
diralik
142

Chociaż pytanie dotyczyło SQL Server 2008 R2, na wypadek, gdyby ktoś czyta to w wersji 2012 i nowszych, od tego czasu stało się to znacznie łatwiejsze dzięki zastosowaniu FORMATU .

Jako argument formatu możesz przekazać standardowy ciąg formatu liczbowego lub niestandardowy ciąg formatu liczbowego (dziękuję Vadimowi Ovchinnikovowi za tę wskazówkę).

Dla tego pytania na przykład taki kod

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

wyjścia

001
001
Géza
źródło
2
Co się stanie, jeśli numer wejściowy to 111 lub 11?
Hogan,
6
Dla 1 to 001, dla 11 to 011, a dla 111 to 111
Géza
2
Możesz użyć „D3” zamiast „00 #”.
Vadim Ovchinnikov
1
wydaje się być znacznie wolniejszy niż zaakceptowana odpowiedź, ale o wiele łatwiejszy, jeśli nie działa z dużą ilością danych
root
2
Chociaż wydaje się to nielogiczne, warto zauważyć, że FORMAT działa tylko z typami liczbowymi i datami, a nie z varchar.
strattonn
120

Bezpieczna metoda:

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

Ma to tę zaletę, że zwraca ciąg '***'dla n <0 lub n> 999, co jest ładnym i oczywistym wskaźnikiem danych wejściowych poza zakresem. Inne metody wymienione tutaj zawiodą po cichu przez obcięcie danych wejściowych do 3-znakowego podłańcucha.

Zaraz
źródło
10
Cholera, ktokolwiek wyląduje na tej stronie, powinien pomóc temu wspiąć się na szczyt!
MarioDS,
1
Korzystaj z tej metody. Gdy wyrażenie przekroczy określoną długość, łańcuch zwraca ** dla określonej długości. na przykład str (n, 10), gdy n = 1000000000, wtedy pojawią się gwiazdki (*).
Bez zobowiązań
Nie wiem, jak to działa, ale jest niesamowite i proste.
RaRdEvA
1
Ostrożnie z tym, ciągi go łamią (a OP poprosił o „wypełnienie sznurka”). Działa: SELECT REPLACE(STR('1',3),' ','0')Przerwy: SELECT REPLACE(STR('1A',3),' ','0'). Właśnie mnie to wypaliło dzisiaj, gdy użytkownik wpisał literę w ciągu wejściowym, a ja nie przetestowałem tego przypadku.
Jeff Mergler,
@ Bez zobowiązań Tak to ma działać, plakat już to mówi. Lepiej zwrócić *** niż wartość obciętą, jak robią to wszystkie inne propozycje, pokazuje to, że parametry były nieprawidłowe.
Marc Guillot
32

Oto bardziej ogólna technika wypełniania lewej strony do dowolnej pożądanej szerokości:

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)

Jeśli jednak masz do czynienia z wartościami ujemnymi i dopełnianiem zer wiodących, ani ta, ani inna sugerowana technika nie będzie działać. Otrzymasz coś, co wygląda następująco:

00-123

[Prawdopodobnie nie to, co chciałeś]

Więc… będziesz musiał przeskoczyć kilka dodatkowych obręczy Oto jedno podejście, które odpowiednio sformatuje liczby ujemne:

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
         )

Należy zauważyć, że convert()wywołania powinny określać [n]varchardługość wystarczającą do przechwycenia przekonwertowanego wyniku z obcięciem.

Nicholas Carey
źródło
2
@StenPetrov, dziękuję. Wszystko zależy od tego, co próbujesz osiągnąć. Jedną z rzeczy, na których nauczyłem się polegać w dużych rzeczywistych bazach danych produkcyjnych, jest obecność złych danych tego rodzaju lub innych. I wolę unikać połączeń telefonicznych o trzeciej nad ranem, jeśli to możliwe; ^)
Nicholas Carey
:) wciąż, gdy pojawia się połączenie 3AM, wolałbym przeczytać 1 prostą linię niż 10 skomplikowanych. Dodanie zmiennych dodatkowo pogarsza sytuację, zwłaszcza jeśli inny członek zespołu postanowił je obliczyć w locie i nie sprawdził nieujemnej @width ...
Sten Petrov
Te dodane zmienne służą jedynie uogólnieniu - wartości można zakodować na stałe. W przypadku jednej wkładki możesz utworzyć funkcję skalarną - wtedy masz swoją jedną wkładkę.
Gerard ONeill
30

Oto wariant odpowiedzi Hogana, której używam w SQL Server Express 2012:

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

Zamiast martwić się, czy pole jest łańcuchem, czy nie, po prostu CONCATgo, ponieważ i tak wyświetli łańcuch. Dodatkowo, jeśli pole może być a NULL, użycie ISNULLmoże być konieczne, aby uniknąć uzyskiwania NULLwyników przez funkcję .

SELECT RIGHT(CONCAT('000', ISNULL(field,'')), 3)
jahu
źródło
1
O ile pamiętam CONCAT ignoruje wartość, jeśli jest ona pusta, więc pierwsza działa dobrze.
Marie
To rozwiązanie działałoby bez względu na długość Field
Unbound
23

Zawsze uważałem, że następująca metoda jest bardzo pomocna.

REPLICATE('0', 5 - LEN(Job.Number)) + CAST(Job.Number AS varchar) as 'NumberFull'
Rachunek
źródło
15

Użyj tej funkcji, która pasuje do każdej sytuacji.

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

Próbka wyjściowa

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 
Salar
źródło
To powinna być zaakceptowana odpowiedź, ponieważ działa na liczbach i ciągach . A jeśli nie chcesz używać funkcji (ale dlaczego nie), coś takiego również działa: DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 12 - LEN(@NumStr)) + @NumStr;co zwraca pierwszy przykład Salara powyżej. Dzięki Salar.
Jeff Mergler,
Mój komentarz powyżej zawiera literówkę, powinien brzmieć: DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 10 - LEN(@NumStr)) + @NumStr;co zwraca 0000002016pierwszy przykład powyżej.
Jeff Mergler,
@JeffMergler - jak to działa na liczbach i ciągach? Jest to funkcja, która przyjmuje parametr liczby całkowitej. Pytanie dotyczyło strun.
Hogan
5

Dla tych, którzy chcą zaktualizować swoje istniejące dane, oto zapytanie:

update SomeEventTable set eventTime=RIGHT('00000'+ISNULL(eventTime, ''),5)
Alan B. Dee
źródło
3

W przypadku liczb całkowitych możesz użyć niejawnej konwersji z int na varchar:

SELECT RIGHT(1000 + field, 3)
Konstantin
źródło
4
Jednak to się nie powiedzie, biorąc pod uwagę wystarczająco dużą wartość, a ponadto w przypadku wartości ujemnych otrzymasz ... ciekawe wyniki.
Nicholas Carey,
3

Znam jego stary bilet, po prostu chciałem go udostępnić.

Znalazłem ten kod szukający rozwiązania. Nie jestem pewien, czy to działa na wszystkich wersjach MSSQL Mam MSSQL 2016.

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

zwraca „0023” 4 w funkcji STR to całkowita długość łącznie z wartością. Przykłady 4, 23 i 123 będą miały 4 w STR i zostanie dodana poprawna liczba zer. Możesz go zwiększyć lub zmniejszyć. Nie musisz uzyskiwać długości na 23.

Edycja: Widzę, że jest taki sam jak post @Anon.

Niel Kupuje
źródło
2

Miałem podobny problem z kolumną całkowitą jak wejście, gdy potrzebowałem wyjścia varchar (lub łańcucha) o stałej wielkości. Na przykład od 1 do „01”, od 12 do „12”. Ten kod działa:

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

Jeśli wejście jest również kolumną varchar, możesz uniknąć części odlewniczej.

użytkownik3183867
źródło
2

Aby uzyskać bardziej dynamiczne podejście, wypróbuj to.

declare @val varchar(5)
declare @maxSpaces int
set @maxSpaces = 3
set @val = '3'
select concat(REPLICATE('0',@maxSpaces-len(@val)),@val)
Ncastillo
źródło
2

Wypróbuj to ze stałą długością.

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

select REPLICATE('0', 5 - LEN(123)) + '123'
Dr.Stark
źródło
1

Napisałem to, ponieważ miałem wymagania do określonej długości (9). Wypełnia lewą stronę @pattern TYLKO wtedy, gdy wejście wymaga dopełnienia. Zawsze powinien zwracać długość zdefiniowaną w @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

Zwraca 1234 wejścia

nicky
źródło
1

To proste

Lubić:

DECLARE @DUENO BIGINT
SET @DUENO=5

SELECT 'ND'+STUFF('000000',6-LEN(RTRIM(@DueNo))+1,LEN(RTRIM(@DueNo)),RTRIM(@DueNo)) DUENO
DEBASIS PAUL
źródło
0

Przybyłem tutaj, aby dowiedzieć się, jak przekonwertować przesunięcie strefy czasowej na ciąg strefy czasowej do konwertowania dat na DATETIMEOFFSET w SQL Server 2008. Brutto, ale konieczne.

Potrzebuję więc 1 metody, która poradzi sobie z liczbami ujemnymi i dodatnimi, formatując je na dwa znaki z wiodącym zerem w razie potrzeby. Odpowiedź Anonsa zbliżyła mnie, ale pojawiłyby się ujemne wartości w strefie czasowej0-5 wymagane-05

Więc z drobną poprawką w odpowiedzi, działa to dla wszystkich konwersji godzinnych w strefie czasowej

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'
Czerwony
źródło
-1

Stworzyłem tę funkcję, która obsługuje bigint i jeden wiodący zero lub inny pojedynczy znak (zwrócono maksymalnie 20 znaków) i pozwala na uzyskanie długości wyników mniejszej niż długość liczby wejściowej:

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,' ')
Shane
źródło