Дополните строку начальными нулями, чтобы в SQL Server 2008 было 3 символа


398

У меня есть строка длиной до 3 символов, когда она впервые была создана в SQL Server 2008 R2.

Я хотел бы дополнить его начальными нулями, поэтому, если его первоначальное значение было «1», то новое значение будет «001». Или, если его исходное значение было «23», новое значение «023». Или, если его исходное значение равно «124», то новое значение совпадает с исходным значением.

Я использую SQL Server 2008 R2. Как бы я сделал это с помощью T-SQL?



Ответы:


681

Если поле уже является строкой, это будет работать

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

Если вы хотите, чтобы нули отображались как '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) просто выполняет RIGHT ('000000 '+ ISNULL (поле,' '), 6) не сработало, но RIGHT (RTRIM (' 000000 '+ ISNULL (поле,' ')), 6) сработало.
DWiener

2
о, я понимаю, у вас были пробелы справа от числа, закодированного в виде строки.
Хоган

3
@dwiener, вы получили такое поведение, потому что char - это тип данных фиксированной длины, поэтому в вашем случае char (6) означает 6 символов в длину. Если ваше действительное значение меньше 6, оно дополняется пробелами справа, поэтому предлагаемый ответ даст неверный результат для символа (6).
Яннис Параскевопулос

2
@Hogan, да, но этот вопрос является топ-1 в результатах поиска Google для "SQL добавить начальные нули", поэтому я думаю, что было бы полезно для многих людей (которые не используют sqlserver, но Google этот вопрос) знать, что в других базах данных может существует более удобная функция lpad. Все равно спасибо.
Диралик

142

Хотя вопрос был для SQL Server 2008 R2, в случае, если кто-то читает это с версией 2012 и выше, с тех пор это стало намного проще благодаря использованию FORMAT .

Вы можете передать стандартную строку числового формата или строку пользовательского числового формата в качестве аргумента формата (спасибо Вадиму Овчинникову за эту подсказку).

Для этого вопроса, например, такой код

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 #».
Вадим Овчинников

1
кажется, что он значительно медленнее, чем принятый ответ, но оооочень легче, если не работает с большими объемами данных
root

2
Хотя это кажется нелогичным, стоит отметить, что FORMAT работает только с числовыми типами и типами даты, а не с varchar.
Страттонн

120

Безопасный метод:

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

Это имеет преимущество в том, что возвращает строку '***'для n <0 или n> 999, что является хорошим и очевидным индикатором ввода за пределы. Другие методы, перечисленные здесь, будут молча завершаться ошибкой, обрезая ввод до 3-символьной подстроки.


10
Блин, кто бы ни приземлился на этой странице, должен помочь этому всплыть на вершину!
MarioDS

1
Осторожно с этим методом. Когда выражение превышает указанную длину, строка возвращает ** для указанной длины. например, str (n, 10), когда n = 1000000000, тогда у вас появятся звезды (*).
Unbound

Я не знаю, как это работает, но это удивительно и просто.
РАРДЕВА

1
Осторожно с этим, строки ломают его (и ОП попросил "заполнить строку"). Работает: SELECT REPLACE(STR('1',3),' ','0')Перерывы: SELECT REPLACE(STR('1A',3),' ','0'). Это просто обожгло меня сегодня, когда пользователь ввел букву во входной строке, и мне не удалось протестировать этот случай.
Джефф Мерглер

@ Unbound Это то, как это должно работать, афиша уже говорит это. Лучше вернуть ***, чем усеченное значение, как это делают все другие предложения, это показывает, что параметры были неверными.
Марк Гийо

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 часа ночи, если смогу; ^)
Николас Кэри

:) до сих пор, когда приходит этот 3AM-вызов, я бы предпочел прочитать 1 простую строку, а не 10 сложных. Добавление переменных еще больше ухудшает ситуацию, особенно если другой член команды решил вычислить их на лету и не проверял неотрицательные значения @width ...
Стен Петров

Эти добавленные переменные просто для обобщения - вы можете жестко закодировать значения. Для одного вкладыша вы можете создать скалярную функцию - тогда у вас есть один вкладыш.
Джерард ONeill

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 просто игнорирует значение, если оно равно нулю, поэтому первое работает нормально.
Мари

Это решение будет работать независимо от
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;которое возвращает первый пример Салара выше. Спасибо Салар.
Джефф Мерглер

Мой комментарий выше содержал опечатку, он должен читать: DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 10 - LEN(@NumStr)) + @NumStr;который возвращается 0000002016в первом примере выше.
Джефф Мерглер

@JeffMergler - как это работает с числами и строками? Это функция, которая принимает целочисленный параметр. Вопрос был о строках.
Хоган

5

Для тех, кто хочет обновить свои существующие данные, вот запрос:

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

3

Для целых чисел вы можете использовать неявное преобразование из int в varchar:

SELECT RIGHT(1000 + field, 3)

4
Однако это не удастся, учитывая достаточно большое значение, кроме того, для отрицательных значений вы получите ... интересные результаты.
Николас Кэри

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 сообщение.


3

Попробуйте это с фиксированной длиной.

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

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

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, когда ввод нуждается в заполнении. Всегда должен возвращать длину, определенную в @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

Возвращает 1234input


1

Просто это

Подобно:

DECLARE @DUENO BIGINT
SET @DUENO=5

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

0

Я пришел сюда специально, чтобы выяснить, как можно преобразовать смещение часового пояса в строку часового пояса для преобразования дат в DATETIMEOFFSET в SQL Server 2008. Брутто, но необходимо.

Поэтому мне нужен 1 метод, который справится с отрицательными и положительными числами, отформатировав их в два символа с начальным нулем, если это необходимо. Ответ Anons заставил меня близко, но отрицательные значения часового пояса вышли бы, 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,' ')
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.