La forma más eficiente de T-SQL para rellenar un varchar a la izquierda a una cierta longitud?


En comparación con decir:

REPLICATE(@padchar, @len - LEN(@str)) + @str
Author: Cade Roux, 2008-09-23

17 answers

Esto es simplemente un uso ineficiente de SQL, no importa cómo lo hagas.

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 (asumiendo que necesita el relleno porque está tratando con una longitud fija).

Pero como he dicho, deberías evitar hacer esto en tu base de datos.

 308
Author: AlexCuse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-28 13:10:54

Sé que esto se preguntó originalmente en 2008, pero hay algunas funciones nuevas que se introdujeron con SQL Server 2012. La función de FORMATO simplifica muy bien el relleno dejado con ceros. También realizará la conversión para usted:

declare @n as int = 2
select FORMAT(@n, 'd10') as padWithZeros

Actualización:

Quería probar la eficiencia real de la función de FORMATO yo mismo. Me sorprendió bastante encontrar que la eficiencia no era muy buena en comparación con la respuesta original de AlexCuse. Aunque Me parece que el limpiador de funciones de formato, no es muy eficiente en términos de tiempo de ejecución. La tabla de cuentas que usé 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.

 49
Author: jediCouncilor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:33:26

Varias personas dieron versiones de esto:

right('XXXXXXXXXXXX'+ @str, @n)

Tenga cuidado con eso porque truncará sus datos reales si es más largo que n.

 35
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-06 08:09:58
@padstr = REPLICATE(@padchar, @len) -- this can be cached, done only once

SELECT RIGHT(@padstr + @str, @len)
 15
Author: Sklivvz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 15:52:07

Tal vez una muerte excesiva Tengo estos UDF para rellenar izquierda y 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
 9
Author: TonyP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-05 22:18:07

No estoy seguro de que el método que das sea realmente ineficiente, pero una forma alternativa, siempre y cuando no tenga que ser flexible en la longitud o el carácter de relleno, sería (suponiendo que quieras rellenarlo con "0" a 10 caracteres:

DECLARE
   @pad_characters VARCHAR(10)

SET @pad_characters = '0000000000'

SELECT RIGHT(@pad_characters + @str, 10)
 6
Author: Tom H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-20 15:04:06

En SQL Server 2005 y posteriores puede crear una función CLR para hacer esto.

 2
Author: Kramii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 15:55:04

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, '_')
 2
Author: ila,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 16:01:30

Me gustó la solución vnRocks, aquí está en forma de un udf

create function PadLeft(
      @String varchar(8000)
     ,@NumChars int
     ,@PadChar char(1) = ' ')
returns varchar(8000)
as
begin
    return stuff(@String, 1, 0, replicate(@PadChar, @NumChars - len(@String)))
end
 2
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-28 15:11:45

Esta es una forma sencilla de rellenar la izquierda:

REPLACE(STR(FACT_HEAD.FACT_NO, x, 0), ' ', y)

Donde x es el número del pad y y es el carácter del pad.

Muestra:

REPLACE(STR(FACT_HEAD.FACT_NO, 3, 0), ' ', 0)
 2
Author: Ahmad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-20 15:03:06
select right(replicate(@padchar, @len) + @str, @len)
 1
Author: Gordon Bell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-23 15:54:41

Espero que esto ayude a alguien.

STUFF (character_expression , start , length ,character_expression)

Seleccionar cosas (@str, 1, 0, replicar ('0', @n - len (@str)))

 1
Author: vnRock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-16 13:34:43

¿qué tal esto:

replace((space(3 - len(MyField))

3 es el número de zeros a pad

 1
Author: joshblair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-15 12:12:16

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 manera 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.

 0
Author: mattpm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-19 17:49:49

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 se encuentre.

/*===============================================================
 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 kilometraje puede variar. :-)

Joey Morgan
Programador / Analista Principal I
WellPoint Medicaid Business Unit

 0
Author: Joseph Morgan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-21 20:08:51

Aquí está mi solución, que evita cadenas truncadas y utiliza 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;
 0
Author: Mass Dot Net,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-25 19:44:37

Así es como normalmente rellenaría un varchar

WHILE Len(@String) < 8
BEGIN
    SELECT @String = '0' + @String
END
 -4
Author: Deanos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-21 12:06:54