Самый эффективный способ T-SQL для размещения varchar слева до определенной длины?

По сравнению с тем, что:

REPLICATE(@padchar, @len - LEN(@str)) + @str

Ответ 1

Это просто неэффективное использование SQL, независимо от того, как вы это делаете.

возможно что-то вроде

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

где X - ваш символ заполнения, а @n - количество символов в результирующей строке (при условии, что вам нужно заполнить, потому что вы имеете дело с фиксированной длиной).

Но, как я сказал, вам действительно следует избегать этого в своей базе данных.

Ответ 2

Я знаю, что об этом изначально спрашивали еще в 2008 году, но есть некоторые новые функции, которые были введены в SQL Server 2012. Функция FORMAT упрощает заполнение слева нулями. Он также выполнит преобразование для вас:

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

Обновление:

Я хотел проверить фактическую эффективность функции FORMAT самостоятельно. Я был очень удивлен, обнаружив, что эффективность оказалась не очень хорошей по сравнению с первоначальным ответом от AlexCuse. Хотя я считаю, что функция FORMAT более чистая, она не очень эффективна с точки зрения времени выполнения. Таблица Tally, которую я использовал, насчитывает 64 000 записей. Слава Мартину Смиту за указание эффективности времени выполнения.

SET STATISTICS TIME ON
select FORMAT(N, 'd10') as padWithZeros from Tally
SET STATISTICS TIME OFF

Время выполнения SQL Server:  Время ЦП = 2157 мс, прошедшее время = 2696 мс.

SET STATISTICS TIME ON
select right('0000000000'+ rtrim(cast(N as varchar(5))), 10) from Tally
SET STATISTICS TIME OFF

Время выполнения SQL Server:

CPU time = 31 ms, elapsed time = 235 ms.

Ответ 3

Несколько человек дали варианты этого:

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

будьте осторожны с этим, потому что он усечет ваши фактические данные, если он длиннее n.

Ответ 4

@padstr = REPLICATE(@padchar, @len) -- this can be cached, done only once

SELECT RIGHT(@padstr + @str, @len)

Ответ 5

Возможно, над убийством у меня есть эти UDF для ввода влево и вправо

ALTER   Function [dbo].[fsPadLeft](@var varchar(200),@padChar char(1)='0',@len int)
returns varchar(300)
as
Begin

return replicate(@PadChar,@len-Len(@var))[email protected]

end

и справа

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

Ответ 6

Я не уверен, что метод, который вы даете, действительно неэффективен, но альтернативный способ, если он не должен быть гибким по длине или дополняющему символу, будет (если вы хотите, чтобы он имеет от "0" до 10 символов:

DECLARE
   @pad_characters VARCHAR(10)

SET @pad_characters = '0000000000'

SELECT RIGHT(@pad_characters + @str, 10)

Ответ 7

Вероятно, overkill, я часто использую этот 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

Чтобы вы могли делать такие вещи, как:

select dbo.f_pad_before('aaa', 10, '_')

Ответ 8

это простой способ проложить влево:

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

Где x - номер пэда, а y - символ колодки.

Пример:

REPLACE(STR(FACT_HEAD.FACT_NO, 3, 0), ' ', 0)

Ответ 9

Мне понравилось решение vnRocks, вот оно в форме 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

Ответ 10

select right(replicate(@padchar, @len) + @str, @len)

Ответ 11

В SQL Server 2005 и более поздних версиях для этого можно создать функцию CLR.

Ответ 12

Как насчет этого:

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

3 - число zeros для ввода

Ответ 13

Я надеюсь, что это поможет кому-то.

STUFF ( character_expression , start , length ,character_expression )

select stuff(@str, 1, 0, replicate('0', @n - len(@str)))

Ответ 14

Я использую этот. Он позволяет определить длину, по которой вы хотите получить результат, а также символ заполнения по умолчанию, если он не указан. Конечно, вы можете настроить длину ввода и вывода для любых максимальных значений, которые вы используете.

/*===============================================================
 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

Ваш пробег может отличаться.:-)

Джои Морган
Программист/главный аналитик я
Бизнес-единица WellPoint Medicaid

Ответ 15

Здесь мое решение, которое позволяет избежать усеченных строк и использует простой OL SQL. Благодаря @AlexCuse, @Kevin и @Sklivvz, решения которых являются основой этого кода.

 --[@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][email protected], [@maxLengthOfPaddedString][email protected];

-- 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;

Ответ 16

Я знаю, что это немного добавляет к разговору в данный момент, но я запускаю процедуру генерации файлов, и она идет невероятно медленно. Я использовал дубликат и увидел этот метод обрезки и решил, что я попробую.

Вы можете видеть в моем коде, где переключение между ними является дополнением к новой переменной @padding (и ограничению, которое сейчас существует). Я выполнил свою процедуру с функцией в обоих состояниях с одинаковыми результатами во время выполнения. Так что, по крайней мере, в SQLServer2016 я не вижу никакой разницы в эффективности, которую нашли другие.

В любом случае, вот мой UDF, который я написал несколько лет назад, плюс сегодняшние изменения, которые во многом совпадают с другими, за исключением того, что у него есть параметр параметра LEFT/RIGHT и некоторая проверка ошибок.

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

Ответ 17

У меня есть одна функция, которая lpad с х десятичных знаков: СОЗДАТЬ ФУНКЦИЮ [dbo]. [LPAD_DEC] (   - Добавить параметры для функции здесь   @pad nvarchar (MAX),   @string nvarchar (MAX),   @length int,   @dec int ) ВОЗВРАЩАЕТСЯ nvarchar (max) КАК НАЧАТЬ   - Объявите возвращаемую переменную здесь   ОБЪЯВИТЬ @resp nvarchar (макс.)

IF LEN(@string)[email protected]
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

END

Ответ 18

Чтобы обеспечить числовые значения, округленные до двух знаков после запятой, но при необходимости с нулями, с нулями:

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)

Если кто-то может подумать о более аккуратном способе, это было бы оценено - вышеупомянутое кажется неуклюжим.

Примечание. В этом случае я использую SQL Server для отправки отчетов по электронной почте в формате HTML и поэтому хочу отформатировать информацию без привлечения дополнительного инструмента для анализа данных.

Ответ 19

Вот как я обычно накладываю varchar

WHILE Len(@String) < 8
BEGIN
    SELECT @String = '0' + @String
END