Прокладіть рядок з провідними нулями, так що це три символи в 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)

Якщо ви хочете, щоб нулі відображалися як "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) не працювало, але ПРАВО (RTRIM (' 000000 '+ ISNULL (поле,' ')), 6).
DWiener

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

3
@dwiener Ви отримали таку поведінку, тому що char є типом даних фіксованої довжини, тож у вашому випадку char (6) означає 6 символів. Якщо фактичне значення менше 6, воно зафіксовано пробілами праворуч, щоб запропонована відповідь дала неправильний результат для позначки (6).
Giannis Paraskevopoulos

2
@Hogan, так, але це питання є результатом google top1 для "sql додати провідні нулі", тому я думаю, що багатьом людям (які не використовують sqlserver, але Google це питання) було б корисно знати, що в інших базах даних можуть бути існує більш зручна функція lpad. В будь-якому випадку, дякую.
diralik

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 працює лише з числовими типами та типами дат, а не з варчаром.
strattonn

120

Безпечний метод:

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

Це має перевагу повернення рядка '***'для n <0 або n> 999, що є приємним і очевидним показником введення поза межами діапазону. Інші перераховані тут способи будуть беззвучно відрізати вхід в 3-символьну підрядку.


10
Чорт, хто хто приземлиться на цій сторінці, повинен допомогти цьому пливти на вершину!
MarioDS

1
Будьте уважні з цим методом. Коли вираз перевищує вказану довжину, рядок повертається ** за вказану довжину. наприклад, str (n, 10), коли n = 1000000000, тоді у вас з’являться зірки (*).
незв'язане

Я не знаю, як це працює, але дивно і просто.
RaRdEvA

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його, оскільки воно все одно виведе рядок. Крім того, якщо поле може бути а NULL, ISNULLможливо, знадобиться використання, щоб уникнути отримання функцій NULLрезультатів.

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

1
Наскільки я пам’ятаю, CONCAT просто ігнорує значення, якщо воно є нульовим, тому перший працює добре.
Марі

Це рішення спрацювало б незалежно від польового поля
Не пов'язане

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.


2

У мене була аналогічна проблема з цілим стовпцем як вхід, коли мені потрібен був вихід фіксованого розміру (або рядок). Наприклад, від 1 до '01', 12 до '12'. Цей код працює:

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

Якщо вхід є також стовпцем варшара, ви можете уникнути частини лиття.


2

Для більш динамічного підходу спробуйте це.

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

2

Спробуйте це з фіксованою довжиною.

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

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

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

Повертає 1234вхід


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.