Respuestas:
Esto es simplemente un uso ineficiente de SQL, sin importar cómo lo haga.
tal vez algo como
right('XXXXXXXXXXXX'+ rtrim(@str), @n)
donde X es su carácter de relleno y @n es el número de caracteres en la cadena resultante (suponiendo que necesita el relleno porque se trata de una longitud fija).
Pero como dije, realmente deberías evitar hacer esto en tu base de datos.
RTRIM(@str)
embargo, es posible que deba hacerlo si puede contener espacios finales.
Sé que esto se solicitó originalmente en 2008, pero hay algunas funciones nuevas que se introdujeron con SQL Server 2012. La función FORMAT simplifica muy bien el relleno dejado con ceros. También realizará la conversión por usted:
declare @n as int = 2
select FORMAT(@n, 'd10') as padWithZeros
Actualizar:
Yo mismo quería probar la eficacia real de la función FORMATO. Me sorprendió bastante descubrir que la eficiencia no era muy buena en comparación con la respuesta original de AlexCuse . Aunque encuentro que la función FORMAT es más limpia, no es muy eficiente en términos de tiempo de ejecución. La tabla Tally que utilicé tiene 64,000 registros. Felicitaciones a Martin Smith por señalar la eficiencia del tiempo de ejecución.
SET STATISTICS TIME ON
select FORMAT(N, 'd10') as padWithZeros from Tally
SET STATISTICS TIME OFF
Tiempos de ejecución de SQL Server: tiempo de CPU = 2157 ms, tiempo transcurrido = 2696 ms.
SET STATISTICS TIME ON
select right('0000000000'+ rtrim(cast(N as varchar(5))), 10) from Tally
SET STATISTICS TIME OFF
Tiempos de ejecución de SQL Server:
Tiempo de CPU = 31 ms, tiempo transcurrido = 235 ms.
Tal vez una matanza excesiva tengo estos UDF para rellenar de izquierda a derecha
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
y a la derecha
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
No estoy seguro de que el método que proporcione sea realmente ineficiente, pero una forma alternativa, siempre que no tenga que ser flexible en la longitud o el carácter de relleno, sería (suponiendo que quiera rellenarlo con " 0 "a 10 caracteres:
DECLARE
@pad_characters VARCHAR(10)
SET @pad_characters = '0000000000'
SELECT RIGHT(@pad_characters + @str, 10)
probablemente exagerado, a menudo uso este 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 puedas hacer cosas como:
select dbo.f_pad_before('aaa', 10, '_')
Esta es una manera simple de rellenar a la izquierda:
REPLACE(STR(FACT_HEAD.FACT_NO, x, 0), ' ', y)
Dónde x
está el número de pad y y
el carácter del pad.
muestra:
REPLACE(STR(FACT_HEAD.FACT_NO, 3, 0), ' ', 0)
1
convierte 001
.
select right(replicate(@padchar, @len) + @str, @len)
Yo uso este Le permite determinar la longitud que desea que tenga el resultado, así como un carácter de relleno predeterminado si no se proporciona uno. Por supuesto, puede personalizar la longitud de la entrada y la salida para los máximos que esté buscando.
/*===============================================================
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
Su experiencia puede ser diferente. :-)
Joey Morgan
Programador / Analista Director I
Unidad de Negocio de WellPoint Medicaid
Aquí está mi solución, que evita cadenas truncadas y usa SQL simple. Gracias a @AlexCuse , @Kevin y @Sklivvz , cuyas soluciones son la base de este 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;
Sé que esto no está agregando mucho a la conversación en este momento, pero estoy ejecutando un procedimiento de generación de archivos y va increíblemente lento. He estado usando replicar y vi este método de recorte y pensé que lo probaría.
Puede ver en mi código dónde el cambio entre los dos es adicional a la nueva variable @padding (y la limitación que ahora existe). Ejecuté mi procedimiento con la función en ambos estados con los mismos resultados en tiempo de ejecución. Entonces, al menos en SQLServer2016, no veo ninguna diferencia en la eficiencia que otros encontraron.
De todos modos, aquí está mi UDF que escribí hace años más los cambios de hoy, que es muy similar al de otro, ya que tiene una opción de parámetro IZQUIERDA / DERECHA y alguna comprobación de errores.
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
Tengo una función que lpad con x decimales: CREATE FUNCTION [dbo]. [LPAD_DEC] (- Agregue los parámetros para la función aquí @pad nvarchar (MAX), @string nvarchar (MAX), @length int, @dec int ) DEVOLUCIONES nvarchar (max) COMO COMIENZO - Declare aquí la variable de retorno 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
FINAL
Para proporcionar valores numéricos redondeados a dos decimales pero rellenados a la derecha con ceros si es necesario, tengo:
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)
Si alguien puede pensar en una forma más ordenada, eso sería apreciado: lo anterior parece torpe .
Nota : en este caso, estoy usando SQL Server para enviar informes por correo electrónico en formato HTML y, por lo tanto, deseo formatear la información sin involucrar una herramienta adicional para analizar los datos.
Así es como normalmente rellenaría un varchar
WHILE Len(@String) < 8
BEGIN
SELECT @String = '0' + @String
END