Preencher uma cadeia de caracteres com zeros à esquerda, para ter 3 caracteres no SQL Server 2008

398

Eu tenho uma cadeia de caracteres com até 3 caracteres quando é criada pela primeira vez no SQL Server 2008 R2.

Gostaria de preenchê-lo com zeros à esquerda, portanto, se seu valor original fosse '1', o novo valor seria '001'. Ou se seu valor original era '23', o novo valor é '023'. Ou, se o valor original for '124', o novo valor será igual ao valor original.

Estou usando o SQL Server 2008 R2. Como eu faria isso usando o T-SQL?

Sunil
fonte

Respostas:

681

Se o campo já for uma string, isso funcionará

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

Se você deseja que os nulos sejam exibidos como '000'

Pode ser um número inteiro - então você deseja

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

Conforme exigido pela pergunta, essa resposta só funciona se o comprimento for <= 3; se você quiser algo maior, precisará alterar a constante da string e as duas constantes inteiras para a largura necessária. por exemplo'0000' and VARCHAR(4)),4

Hogan
fonte
8
Eu tinha um campo Char (6) que tinha um punhado de valores que tinham apenas 2-3 caracteres e o acima não funcionou para mim. Eu tive que adicionar um RTRIM em torno do '000000' + ISNULL (FIELD, '') para que ele funcionasse.
DWiener
3
Hogan, sim, eu entendi, mas não importa quanto tempo a string não funcionou, estou um pouco ocupado para descobrir o porquê, mas a essência disso é que, com o meu campo CHAR (6), apenas RIGHT ('000000 '+ ISNULL (campo,' '), 6) não funcionou, mas RIGHT (RTRIM (' 000000 '+ ISNULL (campo,' ')), 6) funcionou.
DWiener
2
oh, eu entendo, você tinha espaços à direita de um número codificado como uma string.
Hogan
3
@ dwiener você tem esse comportamento porque um caractere é um tipo de dados de comprimento fixo; portanto, no seu caso, char (6) significa 6 caracteres. Se o seu valor real for menor que 6, ele será preenchido com espaços em branco à direita, para que a resposta proposta produza um resultado incorreto para um caractere (6).
Giannis Paraskevopoulos
2
@ Hogan, sim, mas esta pergunta é o resultado top1 do google para "sql add zeros à esquerda", então acho que seria útil para muitas pessoas (que não usam sqlserver, mas pesquisam no google esta pergunta) saberem que em outros bancos de dados podem existe uma função mais conveniente lpad. Obrigado mesmo assim.
diralik
142

Embora a pergunta fosse para o SQL Server 2008 R2, no caso de alguém estar lendo isso com a versão 2012 e superior, desde então, ficou muito mais fácil com o uso do FORMAT .

Você pode passar uma sequência de formato numérico padrão ou uma sequência de formato numérico personalizado como argumento de formato (agradeça a Vadim Ovchinnikov por esta dica).

Para esta pergunta, por exemplo, um código como

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

saídas

001
001
Géza
fonte
2
O que acontece se o número de entrada for 111 ou 11?
Hogan
6
Para 1, é 001, para 11, é 011, e para 111, é 111
Géza
2
Você pode usar 'D3' em vez de '00 # '.
Vadim Ovchinnikov
11
parece ser consideravelmente mais lento do que a resposta aceita, mas sooo muito mais fácil se não trabalhar com grandes quantidades de dados
raiz
2
Embora pareça ilógico, é importante notar que o FORMAT funciona apenas com tipos numéricos e de datas, e não com varchar.
strattonn
120

O método seguro:

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

Isso tem a vantagem de retornar a string '***'para n <0 ou n> 999, que é um bom e óbvio indicador de entrada fora dos limites. Os outros métodos listados aqui falharão silenciosamente, truncando a entrada em uma substring de 3 caracteres.

Anon
fonte
10
Porra, quem chegar nesta página deve ajudar a flutuar para o topo!
MarioDS 3/11
11
Tenha cuidado com este método. Quando a expressão excede o comprimento especificado, a cadeia retorna ** para o comprimento especificado. por exemplo, str (n, 10), quando n = 1000000000, você terá estrelas (*) aparecendo.
Não vinculado
Não sei como isso funciona, mas é incrível e simples.
RaRdEvA 15/02/19
11
Cuidado com este, as cordas quebram (e o OP pediu "preenchendo uma corda"). Funciona: SELECT REPLACE(STR('1',3),' ','0')Breaks: SELECT REPLACE(STR('1A',3),' ','0'). Isso me queimou hoje quando um usuário digitou uma letra na string de entrada e eu não testei esse caso.
Jeff Mergler
@Unbound É assim que deve funcionar, o cartaz já diz. Melhor retornar *** do que um valor truncado, como todas as outras propostas, mostra que os parâmetros estavam incorretos.
Marc Guillot
32

Aqui está uma técnica mais geral para preenchimento à esquerda em qualquer largura desejada:

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)

No entanto, se você estiver lidando com valores negativos e preenchendo com zeros à esquerda, nem isso nem outras técnicas sugeridas funcionarão. Você obterá algo parecido com isto:

00-123

[Provavelmente não é o que você queria]

Então ... você terá que passar por alguns obstáculos adicionais. Aqui está uma abordagem que formata corretamente os números negativos:

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
         )

Deve-se observar que as convert()chamadas devem especificar um [n]varcharcomprimento suficiente para reter o resultado convertido com truncamento.

Nicholas Carey
fonte
2
@StenPetrov, obrigado. Tudo depende do que você está tentando realizar. A única coisa em que aprendi a depender de grandes bancos de dados de produção do mundo real é a presença de dados ruins de um tipo ou de outro. E eu prefiro evitar os telefonemas 3 am Se eu puder; ^)
Nicholas Carey
:) ainda, quando chega a ligação às 3 da manhã, prefiro ler 1 linha simples do que 10 linhas complexas. Adicionando variáveis ainda torna as coisas piores, especialmente se outro membro da equipe decidiu calculá-los em tempo real e não verificar se há @largura não negativo ...
Sten Petrov
Essas variáveis ​​adicionadas são apenas para generalização - você pode codificar os valores. Para um liner, você pode criar uma função escalar - então você tem um liner.
precisa saber é o seguinte
30

Aqui está uma variante da resposta de Hogan, que eu uso no SQL Server Express 2012:

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

Em vez de me preocupar se o campo é uma sequência ou não, eu apenas o faço CONCAT, pois ele produzirá uma sequência de qualquer maneira. Além disso, se o campo puder ser a NULL, ISNULLpode ser necessário usar para evitar que a função obtenha NULLresultados.

SELECT RIGHT(CONCAT('000', ISNULL(field,'')), 3)
jahu
fonte
11
Tanto quanto me lembro, o CONCAT simplesmente ignora o valor se for nulo, portanto o primeiro funciona bem.
314 Marie
Esta solução funcionaria independentemente do len do Field
Não consolidado
23

Sempre achei o método a seguir muito útil.

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

Use esta função que se adapte a todas as situações.

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

Saída de amostra

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
fonte
Essa deve ser a resposta aceita, pois funciona em números e seqüências de caracteres . E se você não quiser usar uma função (mas por que não), algo assim também funciona: o DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 12 - LEN(@NumStr)) + @NumStr;que retorna o primeiro exemplo de Salar acima. Obrigado Salar.
Jeff Mergler
Meu comentário acima continha um erro de digitação, que deveria ser: DECLARE @NumStr VARCHAR(250) = '2016'; SELECT REPLICATE('0', 10 - LEN(@NumStr)) + @NumStr;que retorna 0000002016no primeiro exemplo acima.
Jeff Mergler
@JeffMergler - como isso funciona em números e seqüências de caracteres? É uma função que aceita um parâmetro inteiro. A pergunta era sobre cordas.
Hogan
5

Para aqueles que desejam atualizar seus dados existentes, aqui está a consulta:

update SomeEventTable set eventTime=RIGHT('00000'+ISNULL(eventTime, ''),5)
Alan B. Dee
fonte
3

Para números inteiros, você pode usar a conversão implícita de int para varchar:

SELECT RIGHT(1000 + field, 3)
Konstantin
fonte
4
No entanto, isso falhará se um valor suficientemente grande, além disso, para valores negativos, você obterá ... resultados interessantes.
Nicholas Carey
3

Eu conheço o seu bilhete antigo, só pensei em compartilhá-lo.

Encontrei este código procurando uma solução. Não tenho certeza se funciona em todas as versões do MSSQL, tenho o MSSQL 2016.

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

retorna "0023" O 4 na função STR é o comprimento total, incluindo o valor. Os exemplos 4, 23 e 123 terão 4 em STR e a quantidade correta de zeros será adicionada. Você pode aumentar ou diminuir. Não há necessidade de obter o comprimento no 23.

Editar: vejo o mesmo que a publicação @Anon.

Niel Buys
fonte
3

Tente isso com comprimento fixo.

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

select REPLICATE('0', 5 - LEN(123)) + '123'
Dr.Stark
fonte
2

Eu tive um problema semelhante com a coluna inteira como entrada quando eu precisava de saída varchar de tamanho fixo (ou string). Por exemplo, 1 a '01', 12 a '12'. Este código funciona:

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

Se a entrada também for uma coluna de varchar, você poderá evitar a peça de vazamento.

user3183867
fonte
2

Para uma abordagem mais dinâmica, tente isso.

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

Escrevi isso porque eu tinha requisitos para um comprimento específico (9). Almofada à esquerda com o @pattern SOMENTE quando a entrada precisar de preenchimento. Sempre deve retornar o comprimento definido em @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

Retorna 1234input

Nicky
fonte
1

Simples é isso

Gostar:

DECLARE @DUENO BIGINT
SET @DUENO=5

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

Eu vim aqui especificamente para descobrir como poderia converter meu fuso horário para uma string de fuso horário para converter datas em DATETIMEOFFSET no SQL Server 2008. Bruto, mas necessário.

Então, eu preciso de um método que lide com números negativos e positivos, formatando-os para dois caracteres com um zero à esquerda, se necessário. A resposta de Anons me aproximou, mas os valores negativos do fuso horário apareceriam mais 0-5do que os necessários-05

Então, com um pouco de ajuste em sua resposta, isso funciona para todas as conversões de fuso horário

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'
Vermelho
fonte
-1

Eu criei essa função que atende bigint e um zero inicial ou outro caractere único (máximo de 20 caracteres retornados) e permite resultados menores que o número de entrada:

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
fonte