Respostas:
Este é simplesmente um uso ineficiente do SQL, não importa como você o faça.
talvez algo como
right('XXXXXXXXXXXX'+ rtrim(@str), @n)
onde X é seu caractere de preenchimento e @n é o número de caracteres na sequência resultante (supondo que você precise do preenchimento porque está lidando com um comprimento fixo).
Mas como eu disse, você realmente deve evitar fazer isso no seu banco de dados.
RTRIM(@str)
se isso puder conter espaços à direita.
Eu sei que isso foi solicitado originalmente em 2008, mas há algumas novas funções que foram introduzidas no SQL Server 2012. A função FORMAT simplifica o preenchimento deixado com zeros. Também realizará a conversão para você:
declare @n as int = 2
select FORMAT(@n, 'd10') as padWithZeros
Atualizar:
Eu queria testar a eficiência real da função FORMAT. Fiquei bastante surpreso ao descobrir que a eficiência não era muito boa em comparação com a resposta original do AlexCuse . Embora eu ache a função FORMAT mais limpa, ela não é muito eficiente em termos de tempo de execução. A tabela Tally que usei tem 64.000 registros. Parabéns a Martin Smith por apontar a eficiência do tempo de execução.
SET STATISTICS TIME ON
select FORMAT(N, 'd10') as padWithZeros from Tally
SET STATISTICS TIME OFF
Tempos de execução do SQL Server: tempo de CPU = 2157 ms, tempo decorrido = 2696 ms.
SET STATISTICS TIME ON
select right('0000000000'+ rtrim(cast(N as varchar(5))), 10) from Tally
SET STATISTICS TIME OFF
Tempos de execução do SQL Server:
Tempo de CPU = 31 ms, tempo decorrido = 235 ms.
Talvez um extermínio eu tenha essas UDFs para cobrir esquerda e direita
ALTER Function [dbo].[fsPadLeft](@var varchar(200),@padChar char(1)='0',@len int)
returns varchar(300)
as
Begin
return replicate(@PadChar,@len-Len(@var))+@var
end
e para a direita
ALTER function [dbo].[fsPadRight](@var varchar(200),@padchar char(1)='0', @len int) returns varchar(201) as
Begin
--select @padChar=' ',@len=200,@var='hello'
return @var+replicate(@PadChar,@len-Len(@var))
end
Não tenho certeza de que o método que você fornece seja realmente ineficiente, mas uma maneira alternativa, desde que não precise ser flexível no tamanho ou no caractere de preenchimento, seria (supondo que você queira preenchê-lo com " 0 "a 10 caracteres:
DECLARE
@pad_characters VARCHAR(10)
SET @pad_characters = '0000000000'
SELECT RIGHT(@pad_characters + @str, 10)
provavelmente exagere, costumo usar esse UDF:
CREATE FUNCTION [dbo].[f_pad_before](@string VARCHAR(255), @desired_length INTEGER, @pad_character CHAR(1))
RETURNS VARCHAR(255) AS
BEGIN
-- Prefix the required number of spaces to bulk up the string and then replace the spaces with the desired character
RETURN ltrim(rtrim(
CASE
WHEN LEN(@string) < @desired_length
THEN REPLACE(SPACE(@desired_length - LEN(@string)), ' ', @pad_character) + @string
ELSE @string
END
))
END
Para que você possa fazer coisas como:
select dbo.f_pad_before('aaa', 10, '_')
Esta é uma maneira simples de colocar à esquerda:
REPLACE(STR(FACT_HEAD.FACT_NO, x, 0), ' ', y)
Onde x
está o número do bloco e y
o caractere do bloco.
amostra:
REPLACE(STR(FACT_HEAD.FACT_NO, 3, 0), ' ', 0)
1
se tornam 001
.
select right(replicate(@padchar, @len) + @str, @len)
Eu uso este. Permite determinar o comprimento que você deseja que o resultado seja, além de um caractere de preenchimento padrão, se não houver um. É claro que você pode personalizar o tamanho da entrada e da saída para quaisquer valores máximos em que estiver se deparando.
/*===============================================================
Author : Joey Morgan
Create date : November 1, 2012
Description : Pads the string @MyStr with the character in
: @PadChar so all results have the same length
================================================================*/
CREATE FUNCTION [dbo].[svfn_AMS_PAD_STRING]
(
@MyStr VARCHAR(25),
@LENGTH INT,
@PadChar CHAR(1) = NULL
)
RETURNS VARCHAR(25)
AS
BEGIN
SET @PadChar = ISNULL(@PadChar, '0');
DECLARE @Result VARCHAR(25);
SELECT
@Result = RIGHT(SUBSTRING(REPLICATE('0', @LENGTH), 1,
(@LENGTH + 1) - LEN(RTRIM(@MyStr)))
+ RTRIM(@MyStr), @LENGTH)
RETURN @Result
END
Sua milhagem pode variar. :-)
Joey Morgan
Programador / Analista Principal I
Unidade de Negócios WellPoint Medicaid
Aqui está minha solução, que evita seqüências de caracteres truncadas e usa o SQL simples. Graças a @AlexCuse , @Kevin e @Sklivvz , cujas soluções são a base deste código.
--[@charToPadStringWith] is the character you want to pad the string with.
declare @charToPadStringWith char(1) = 'X';
-- Generate a table of values to test with.
declare @stringValues table (RowId int IDENTITY(1,1) NOT NULL PRIMARY KEY, StringValue varchar(max) NULL);
insert into @stringValues (StringValue) values (null), (''), ('_'), ('A'), ('ABCDE'), ('1234567890');
-- Generate a table to store testing results in.
declare @testingResults table (RowId int IDENTITY(1,1) NOT NULL PRIMARY KEY, StringValue varchar(max) NULL, PaddedStringValue varchar(max) NULL);
-- Get the length of the longest string, then pad all strings based on that length.
declare @maxLengthOfPaddedString int = (select MAX(LEN(StringValue)) from @stringValues);
declare @longestStringValue varchar(max) = (select top(1) StringValue from @stringValues where LEN(StringValue) = @maxLengthOfPaddedString);
select [@longestStringValue]=@longestStringValue, [@maxLengthOfPaddedString]=@maxLengthOfPaddedString;
-- Loop through each of the test string values, apply padding to it, and store the results in [@testingResults].
while (1=1)
begin
declare
@stringValueRowId int,
@stringValue varchar(max);
-- Get the next row in the [@stringLengths] table.
select top(1) @stringValueRowId = RowId, @stringValue = StringValue
from @stringValues
where RowId > isnull(@stringValueRowId, 0)
order by RowId;
if (@@ROWCOUNT = 0)
break;
-- Here is where the padding magic happens.
declare @paddedStringValue varchar(max) = RIGHT(REPLICATE(@charToPadStringWith, @maxLengthOfPaddedString) + @stringValue, @maxLengthOfPaddedString);
-- Added to the list of results.
insert into @testingResults (StringValue, PaddedStringValue) values (@stringValue, @paddedStringValue);
end
-- Get all of the testing results.
select * from @testingResults;
Eu sei que isso não está adicionando muito à conversa neste momento, mas estou executando um procedimento de geração de arquivos e está indo incrivelmente lento. Eu tenho usado replicate e vi esse método de apara e achei que eu daria uma chance.
Você pode ver no meu código onde a alternância entre os dois é uma adição à nova variável @padding (e a limitação que agora existe). Eu executei meu procedimento com a função nos dois estados com os mesmos resultados em tempo de execução. Portanto, pelo menos no SQLServer2016, não estou vendo nenhuma diferença de eficiência encontrada por outros.
De qualquer forma, aqui está a minha UDF que escrevi anos atrás, além das mudanças atuais, que são praticamente as mesmas que as de outras, exceto por ter uma opção de parâmetro ESQUERDA / DIREITA e alguma verificação de erro.
CREATE FUNCTION PadStringTrim
(
@inputStr varchar(500),
@finalLength int,
@padChar varchar (1),
@padSide varchar(1)
)
RETURNS VARCHAR(500)
AS BEGIN
-- the point of this function is to avoid using replicate which is extremely slow in SQL Server
-- to get away from this though we now have a limitation of how much padding we can add, so I've settled on a hundred character pad
DECLARE @padding VARCHAR (100) = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
SET @padding = REPLACE(@padding, 'X', @padChar)
SET @inputStr = RTRIM(LTRIM(@inputStr))
IF LEN(@inputStr) > @finalLength
RETURN '!ERROR!' -- can search for ! in the returned text
ELSE IF(@finalLength > LEN(@inputStr))
IF @padSide = 'L'
SET @inputStr = RIGHT(@padding + @inputStr, @finalLength)
--SET @inputStr = REPLICATE(@padChar, @finalLength - LEN(@inputStr)) + @inputStr
ELSE IF @padSide = 'R'
SET @inputStr = LEFT(@inputStr + @padding, @finalLength)
--SET @inputStr = @inputStr + REPLICATE(@padChar, @finalLength - LEN(@inputStr))
-- if LEN(@inputStr) = @finalLength we just return it
RETURN @inputStr;
END
-- SELECT dbo.PadStringTrim( tblAccounts.account, 20, '~' , 'R' ) from tblAccounts
-- SELECT dbo.PadStringTrim( tblAccounts.account, 20, '~' , 'L' ) from tblAccounts
Eu tenho uma função que lpad com x decimais: CREATE FUNCTION [dbo]. [LPAD_DEC] (- Adicione os parâmetros para a função aqui @pad nvarchar (MAX), @ string nvarchar (MAX), @length int, @dec int ) RETORNA nvarchar (max) AS BEGIN - Declare a variável de retorno aqui DECLARE @resp nvarchar (max)
IF LEN(@string)=@length
BEGIN
IF CHARINDEX('.',@string)>0
BEGIN
SELECT @resp = CASE SIGN(@string)
WHEN -1 THEN
-- Nros negativos grandes con decimales
concat('-',SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(abs(@string),@length,@dec)))
ELSE
-- Nros positivos grandes con decimales
concat(SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(@string,@length,@dec)))
END
END
ELSE
BEGIN
SELECT @resp = CASE SIGN(@string)
WHEN -1 THEN
--Nros negativo grande sin decimales
concat('-',SUBSTRING(replicate(@pad,@length),1,(@length-3)-len(@string)),ltrim(str(abs(@string),@length,@dec)))
ELSE
-- Nros positivos grandes con decimales
concat(SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(@string,@length,@dec)))
END
END
END
ELSE
IF CHARINDEX('.',@string)>0
BEGIN
SELECT @resp =CASE SIGN(@string)
WHEN -1 THEN
-- Nros negativos con decimales
concat('-',SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(abs(@string),@length,@dec)))
ELSE
--Ntos positivos con decimales
concat(SUBSTRING(replicate(@pad,@length),1,@length-len(@string)),ltrim(str(abs(@string),@length,@dec)))
END
END
ELSE
BEGIN
SELECT @resp = CASE SIGN(@string)
WHEN -1 THEN
-- Nros Negativos sin decimales
concat('-',SUBSTRING(replicate(@pad,@length-3),1,(@length-3)-len(@string)),ltrim(str(abs(@string),@length,@dec)))
ELSE
-- Nros Positivos sin decimales
concat(SUBSTRING(replicate(@pad,@length),1,(@length-3)-len(@string)),ltrim(str(abs(@string),@length,@dec)))
END
END
RETURN @resp
FIM
Para fornecer valores numéricos arredondados para duas casas decimais, mas preenchidos à direita com zeros, se necessário, tenho:
DECLARE @value = 20.1
SET @value = ROUND(@value,2) * 100
PRINT LEFT(CAST(@value AS VARCHAR(20)), LEN(@value)-2) + '.' + RIGHT(CAST(@value AS VARCHAR(20)),2)
Se alguém puder pensar de uma maneira mais organizada, isso seria apreciado - o acima parece desajeitado .
Nota : neste caso, estou usando o SQL Server para enviar relatórios por email em formato HTML e, portanto, desejo formatar as informações sem envolver uma ferramenta adicional para analisar os dados.
Aqui está como eu normalmente preencheria um varchar
WHILE Len(@String) < 8
BEGIN
SELECT @String = '0' + @String
END