Самый эффективный способ T-SQL для заполнения varchar слева до определенной длины? - PullRequest
200 голосов
/ 23 сентября 2008

По сравнению с:

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

Ответы [ 18 ]

1 голос
/ 16 июня 2011

Надеюсь, это кому-нибудь поможет.

STUFF ( character_expression , start , length ,character_expression )

select stuff(@str, 1, 0, replicate('0', @n - len(@str)))
1 голос
/ 23 сентября 2008

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

1 голос
/ 24 марта 2009

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

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

3 - это число zeros для дополнения

0 голосов
/ 07 марта 2019

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

Вы можете видеть в моем коде, где переключение между ними является дополнением к новой переменной @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
0 голосов
/ 25 мая 2017

Вот мое решение, которое позволяет избежать усеченных строк и использует простой старый SQL. Спасибо @ AlexCuse , @ Кевину и @ 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]=@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 голосов
/ 22 мая 2013

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

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

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

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

0 голосов
/ 19 марта 2012

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

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 и поэтому хочу отформатировать информацию, не прибегая к дополнительному инструменту для анализа данных.

0 голосов
/ 21 сентября 2011

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

WHILE Len(@String) < 8
BEGIN
    SELECT @String = '0' + @String
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...