왼쪽의 varchar를 특정 길이까지 채우는 가장 효율적인 T-SQL 방법은 무엇입니까?


205

말과 비교하여 :

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

마지막 편집을 롤백했습니다. 질문은 한 가지 방법을 제공합니다-더 최적의 방법을 찾고있었습니다. 편집은 다른 품질을 찾는 데있어 그 의미를 잃었습니다.
Cade Roux

답변:


323

방법에 관계없이 단순히 SQL을 비효율적으로 사용하는 것입니다.

아마도 같은

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

여기서 X는 패딩 문자이고 @n은 결과 문자열의 문자 수입니다 (고정 길이를 처리하기 때문에 패딩이 필요하다고 가정).

그러나 내가 말했듯이 실제로는 데이터베이스 에서이 작업을 수행하지 않아야합니다.


2
예를 들어 페이징 된 화면에 대한 데이터의 하위 집합을 가져 오는 등 필요한 시간이 있습니다.
삐 삐 소리

7
+1 방금 다양한 방법으로 테스트했으며 이것이 가장 빠릅니다. RTRIM(@str)그러나 후행 공백이 포함될 수 있으면 필요할 수 있습니다.
Martin Smith

1
내 문자 (6) 제대로 패딩되지 않은 이유 +1 이상 수수께끼 였고, 입력 변수에 RTRIM은 좀 머리를 긁적 저장
jkelley

@MartinSmith 고맙습니다 ... 나는 왜 내 문자열이 작동하지 않고 rtrim이 그것을 고쳤는지 알아 내려고 노력했습니다. TY.
WernerCD

3
이것은 좋은 대답입니다. 물론 필요하지 않을 때는이 작업을 피해야하지만 때로는 피할 수없는 경우도 있습니다. 필자의 경우 배포 제한으로 인해 C #에서 선택할 수 없으며 프랜차이즈 번호는 앞에 0이있는 5 자의 숫자 문자열이어야 할 때 INT로 저장했습니다. 이것은 엄청나게 도움이되었습니다.
Jim

57

2008 년에 이것이 원래 요청되었지만 SQL Server 2012에 도입 된 몇 가지 새로운 기능이 있습니다. FORMAT 함수 는 왼쪽에 0으로 채워지는 패딩을 단순화합니다. 또한 당신을 위해 변환을 수행합니다 :

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 실행 시간 : CPU 시간 = 2157ms, 경과 시간 = 2696ms

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

SQL Server 실행 시간 :

CPU 시간 = 31ms, 경과 시간 = 235ms


1
이것은 내가 찾던 것입니다. FORMAT 공식 도움말 : msdn.microsoft.com/es-MX/library/hh213505.aspx
Fer García

1
이는 MSDN 및 SQL Server 2012에서 사용해 본 경험에 따라 SQL Server 2014 이상에 적용됩니다.
arame3333

5
그래도 이것은 "가장 효율적인"방법이 아닙니다. 이 예제에서 형식은 180 초 대 12 초가 걸립니다. stackoverflow.com/a/27447244/73226
Martin Smith

2
프로그래머가 그것을 사용하는 데 걸리는 시간면에서 "가장 효율적"일 수 있습니다!
underscore_d

36

여러 사람들이 이것의 버전을 주었다 :

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

실제 데이터가 n보다 길면 잘 리므로주의하십시오.


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

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

9

어쩌면 오버 킬로이 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))+@var

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

스칼라 UDF의 유일한 문제점은 동등한 코드 인라인보다 성능이 훨씬 떨어진다 (데이터 유형 문제가 있음). 다음 버전에서 더 나은 스칼라 UDF 성능 및 / 또는 인라인 스칼라 UDF를 도입하기를 희망합니다.
Cade Roux

var의 길이보다 작은 길이를 지정하면 이러한 함수는 null을 반환합니다. 길이가 짧으면 var를 반환하기 위해 각 replicate 문을 isull 문으로 래핑하십시오. isnull (replicate (...), '')
Jersey Dude

WITH SCHEMABINDING을 함수 선언에 추가하면 사용자 정의 함수의 효율성이 향상됩니다. 제거해야 할 강력한 이유가없는 한 기본적으로 모든 함수에 추가하는 것이 좋습니다.
EricI

7

귀하가 제공하는 방법이 실제로 비효율적이라고 확신 할 수는 없지만 길이나 패딩 문자가 유연하지 않아도되는 한 다른 방법은 다음과 같습니다 ( " 0 "~ 10 자 :

DECLARE
   @pad_characters VARCHAR(10)

SET @pad_characters = '0000000000'

SELECT RIGHT(@pad_characters + @str, 10)

2

아마 과잉일지도 모르지만, 나는 종종이 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, '_')

이것은 실제로 udf에서 사용되며 일부 데이터를 준수하기 위해 몇 가지 다른 작업을 수행해야합니다.
Cade Roux

char 및 varchar 유형을 결합하는 경우에도 완벽하게 작동합니다.
Jimmy Baker

2

나는 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

2

이것은 왼쪽을 채우는 간단한 방법입니다.

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

x패드 번호는 어디에 y있고 패드 문자입니다.

견본:

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

당신은 그 왼쪽 패딩 번호에 대해 이야기 할 것 같다 1된다 001.
Martin Smith


1

SQL Server 2005 이상에서는이를 위해 CLR 함수를 만들 수 있습니다.


1

이건 어때요:

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

3은 zeros패드 수


CONCAT (REPLACE (SPACE (@n-LENGTH (@str)), '', '0'), @str)
ingham

1

나는 이것이 누군가를 돕기를 바랍니다.

STUFF ( character_expression , start , length ,character_expression )

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

0

나는 이것을 사용합니다. 기본 패딩 문자 (제공되지 않은 경우)뿐만 아니라 결과 길이를 결정할 수 있습니다. 물론 최대 길이에 상관없이 입력 및 출력 길이를 사용자 정의 할 수 있습니다.

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

귀하의 마일리지가 다를 수 있습니다. :-)

Joey Morgan
프로그래머 / 분석가 교장 I
WellPoint Medicaid 사업부


0

다음은 잘린 문자열을 피하고 일반 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]=@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

나는 이것이 현재 대화에 많은 것을 추가하지는 않지만 파일 생성 절차를 실행하고 있으며 매우 느리게 진행되고 있음을 알고 있습니다. 나는 복제를 사용하고 있었고이 트림 방법을 보았고 나는 그것을 줄 것이라고 생각했습니다.

내 코드에서 새로운 @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

lpad에 x 10 진수를 갖는 함수가 하나 있습니다 : CREATE FUNCTION [dbo]. [LPAD_DEC] (-함수에 대한 매개 변수를 여기에 @pad nvarchar (MAX), @string nvarchar (MAX), @length int, @dec int 추가 ) nvarchar (max)를 BEGIN으로 반환-여기서 반환 변수를 선언합니다. 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

종료


-1

소수점 이하 두 자리로 반올림하지만 필요한 경우 0으로 오른쪽 채워진 숫자 값을 제공하려면 다음이 있습니다.

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 형식으로 전자 메일로 보내므로 데이터를 구문 분석하는 추가 도구를 사용하지 않고 정보의 형식을 지정하려고합니다.


1
SQL Server에서 변수 유형을 지정하지 않고 변수를 선언 할 수 있다는 것을 몰랐습니다. 어쨌든, 당신의 방법은 작동하지 않는 방법에 대해 "서투른"것 같습니다. :)
Andriy M

-4

다음은 일반적으로 varchar를 채우는 방법입니다.

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

14
와우, 이것은 엄청나게 나쁘다.
Hogan

1
루프, 커서 등은 일반적으로 SQL에서 나쁩니다. 응용 프로그램 코드에는 문제가 없지만 SQL에는 적합하지 않을 수 있습니다. 일부 예외는 있지만이 중 하나가 아닙니다.
Davos
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.