공백 자르기 (공백, 탭, 줄 바꿈)


10

나는 SQL 서버 2014 그리고 난 공백 간단한 공백, 탭 또는 줄 바꿈 (둘 다 될 수있는 칼럼의 내용의 시작과 끝에서 깨끗한 공백에 필요 \n하고 \r\n); 예 :

'    this content    '                          should become 'this content'
'  \r\n   \t\t\t this \r\n content \t  \r\n   ' should become 'this \r\n content'

등등.

나는 첫 번째 사건 만 달성 할 수있었습니다.

UPDATE table t SET t.column = LTRIM(RTRIM(t.column))

그러나 다른 경우에는 작동하지 않습니다.

답변:


8

SQL Server 2017 이상을 사용하는 사람

TRIM 내장 기능을 사용할 수 있습니다 . 예를 들면 다음과 같습니다.

DECLARE @Test NVARCHAR(4000);
SET @Test = N'  
    ' + NCHAR(0x09) + N'  ' + NCHAR(0x09) + N' this 
 ' + NCHAR(0x09) + NCHAR(0x09) + N'  content' + NCHAR(0x09) + NCHAR(0x09) + N'  
' + NCHAR(0x09) + N' ' + NCHAR(0x09) + NCHAR(0x09) + N'     ';

SELECT N'~'
        + TRIM(NCHAR(0x09) + NCHAR(0x20) + NCHAR(0x0D) + NCHAR(0x0A) FROM @Test)
        + N'~';

기본 동작은 TRIM공백 만 제거하는 것이므로 탭과 줄 바꾸기 (CR + LF)도 제거하려면 characters FROM절 을 지정해야합니다 .

또한 예제 코드를 복사하여 붙여 넣고 올바른 문자를 유지할 수 있도록 변수 NCHAR(0x09)의 탭 문자를 사용 했습니다 @Test. 그렇지 않으면이 페이지가 렌더링 될 때 탭이 공백으로 변환됩니다.

SQL Server 2016 이상을 사용하는 사람

SQLCLR Scalar UDF 또는 T-SQL 인라인 TVF (iTVF)로 함수를 작성할 수 있습니다. T-SQL 인라인 TVF는 다음과 같습니다.

CREATE
--ALTER
FUNCTION dbo.TrimChars(@OriginalString NVARCHAR(4000), @CharsToTrim NVARCHAR(50))
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN
WITH cte AS
(
  SELECT PATINDEX(N'%[^' + @CharsToTrim + N']%', @OriginalString) AS [FirstChar],
         PATINDEX(N'%[^' + @CharsToTrim + N']%', REVERSE(@OriginalString)) AS [LastChar],
        LEN(@OriginalString + N'~') - 1 AS [ActualLength]
)
SELECT cte.[ActualLength],
       [FirstChar],
       ((cte.[ActualLength] - [LastChar]) + 1) AS [LastChar],
       SUBSTRING(@OriginalString, [FirstChar],
                 ((cte.[ActualLength] - [LastChar]) - [FirstChar] + 2)) AS [FixedString]
FROM   cte;
GO

그리고 다음과 같이 실행하십시오.

DECLARE @Test NVARCHAR(4000);
SET @Test = N'  
    ' + NCHAR(0x09) + N'  ' + NCHAR(0x09) + N' this 
 ' + NCHAR(0x09) + NCHAR(0x09) + N'  content' + NCHAR(0x09) + NCHAR(0x09) + N'  
' + NCHAR(0x09) + N' ' + NCHAR(0x09) + NCHAR(0x09) + N'     ';

SELECT N'~' + tc.[FixedString] + N'~' AS [proof]
FROM   dbo.TrimChars(@Test, NCHAR(0x09) + NCHAR(0x20) + NCHAR(0x0D) + NCHAR(0x0A)) tc;

보고:

proof
----
~this 
              content~

그리고 당신은 그것을 UPDATEusing 에서 사용할 수 있습니다 CROSS APPLY:

UPDATE tbl
SET    tbl.[Column] = itvf.[FixedString]
FROM   SchemaName.TableName tbl
CROSS APPLY  dbo.TrimChars(tbl.[Column],
                           NCHAR(0x09) + NCHAR(0x20) + NCHAR(0x0D) + NCHAR(0x0A)) itvf

처음에 언급했듯이 .NET에는 Trim()원하는 작업을 정확하게 수행 하는 메서드가 포함되어 있기 때문에 SQLCLR을 통해 쉽게 수행 할 수 있습니다. 직접 호출하도록 코드를 작성 SqlString.Value.Trim()하거나 무료 버전의 SQL # 라이브러리 (내가 생성했지만이 기능은 무료 버전 임)를 설치하고 String_Trim (공백 만 있음) 또는 String_TrimChars를 사용할 수 있습니다 . 위의 iTVF와 같이 양쪽에서 트리밍 할 문자를 전달합니다.

DECLARE @Test NVARCHAR(4000);
SET @Test = N'  
    ' + NCHAR(0x09) + N'  ' + NCHAR(0x09) + N' this 
 ' + NCHAR(0x09) + NCHAR(0x09) + N'  content' + NCHAR(0x09) + NCHAR(0x09) + N'  
' + NCHAR(0x09) + N' ' + NCHAR(0x09) + NCHAR(0x09) + N'     ';

SELECT N'~' + SQL#.String_Trim(@Test) + N'~' AS [proof];

그리고 iTVF 예제 출력에서 ​​위에 표시된 것과 정확히 동일한 문자열을 리턴합니다. 그러나 스칼라 UDF이므로 다음과 같이 사용합니다 UPDATE.

UPDATE tbl
SET    tbl.[Column] = SQL#.String_Trim(itvf.[Column])
FROM   SchemaName.TableName tbl

위의 방법 중 하나는 수백만 행에 걸쳐 효율적이어야합니다. 인라인 TVF는 다중 문 TVF 및 T-SQL 스칼라 UDF와 달리 최적화 할 수 있습니다. 또한 SQLCLR Scalar UDF는 IsDeterministic=trueDataAccess 유형으로 표시되고 Read(사용자 및 시스템 데이터 액세스의 기본값은 모두)으로 설정되지 않은 한 병렬 계획에서 사용될 가능성이 있으며 None, 두 조건은 모두 위에서 언급 한 두 SQLCLR 함수 모두에 해당됩니다.


4

TVF (table-valued-function)를 사용하여 데이터의 시작과 끝에서 문제가되는 문자를 제거하는 것이 좋습니다.

테스트 데이터를 보유 할 테이블을 작성하십시오.

IF COALESCE(OBJECT_ID('dbo.TrimTest'), 0) <> 0
BEGIN
    DROP TABLE dbo.TrimTest;
END
CREATE TABLE dbo.TrimTest
(
    SampleData VARCHAR(50) NOT NULL
);

INSERT INTO dbo.TrimTest (SampleData)
SELECT CHAR(13) + CHAR(10) + CHAR(9) + 'this is ' + CHAR(13) + CHAR(10) + ' a test' + CHAR(13) + CHAR(10);
GO

TVF를 작성하십시오.

IF COALESCE(OBJECT_ID('dbo.StripCrLfTab'), 0) <> 0
BEGIN
    DROP FUNCTION dbo.StripCrLfTab;
END
GO
CREATE FUNCTION dbo.StripCrLfTab
(
    @val NVARCHAR(1000)
)
RETURNS @Results TABLE
(
    TrimmedVal NVARCHAR(1000) NULL
)
AS
BEGIN
    DECLARE @TrimmedVal NVARCHAR(1000);
    SET @TrimmedVal = CASE WHEN RIGHT(@val, 1) = CHAR(13) OR RIGHT(@val, 1) = CHAR(10) OR RIGHT(@val, 1) = CHAR(9)
            THEN LEFT(
                CASE WHEN LEFT(@val, 1) = CHAR(13) OR LEFT(@val, 1) = CHAR(10) OR LEFT(@val, 1) = CHAR(9)
                THEN RIGHT(@val, LEN(@val) - 1)
                ELSE @val
                END
                , LEN(@val) -1 )
            ELSE
                CASE WHEN LEFT(@val, 1) = CHAR(13) OR LEFT(@val, 1) = CHAR(10) OR LEFT(@val, 1) = CHAR(9)
                THEN RIGHT(@val, LEN(@val) - 1)
                ELSE @val
                END
            END;
    IF @TrimmedVal LIKE (CHAR(13) + '%')
        OR @TrimmedVal LIKE (CHAR(10) + '%')
        OR @TrimmedVal LIKE (CHAR(9) + '%')
        OR @TrimmedVal LIKE ('%' + CHAR(13))
        OR @TrimmedVal LIKE ('%' + CHAR(10))
        OR @TrimmedVal LIKE ('%' + CHAR(9))
        SELECT @TrimmedVal = tv.TrimmedVal
        FROM dbo.StripCrLfTab(@TrimmedVal) tv;
    INSERT INTO @Results (TrimmedVal)
    VALUES (@TrimmedVal);
    RETURN;
END;
GO

TVF를 실행하여 결과를 표시하십시오.

SELECT tt.SampleData
    , stt.TrimmedVal
FROM dbo.TrimTest tt
CROSS APPLY dbo.StripCrLfTab(tt.SampleData) stt;

결과 :

여기에 이미지 설명을 입력하십시오

TVF는 함수에 전달 된 문자열의 시작과 끝에 남은 문제 문자가 없을 때까지 재귀 적으로 호출합니다. 이것은 많은 수의 행에서 잘 수행되지는 않지만 데이터베이스에 삽입 될 때 데이터를 수정하기 위해이를 사용하는 경우에는 정상적으로 작동합니다.

업데이트 명령문에서 이것을 사용할 수 있습니다.

UPDATE dbo.TrimTest
SET TrimTest.SampleData = stt.TrimmedVal
FROM dbo.TrimTest tt
CROSS APPLY dbo.StripCrLfTab(tt.SampleData) stt;


SELECT *
FROM dbo.TrimTest;

결과 (텍스트) :

여기에 이미지 설명을 입력하십시오


불행하게도 나는 여러 테이블의 행 (수백만)의 많은 양의를 청소해야합니다, 당신에게 최대 감사, 내가에 사용되는 일부 기능에 희망 UPDATE같은 쿼리 LTRIM/ RTRIM의 라인에 뭔가 UPDATE table t SET t.column = TRIM(t.column, CONCAT(CHAR(9), CHAR(10), CHAR(13)))A를 TRIM( expression, charlist )문자의 목록을 받아들이는 기능을 자릅니다 많은 스크립팅 언어처럼.
Giovanni Lovato

내가 아마 그것에 대해 "경고"많은 행에서 잘 작동하지 않는 경고는 문제가 될 수도 있고 아닐 수도 있습니다. 이 작업을 한 번만 수행하면 문제가되지 않을 수 있습니다. 프로덕션 환경이 아닌 환경에서 테스트하여 시간이 얼마나 걸리는지 확인할 수 있습니다.
Max Vernon

update진술 에서 어떻게 사용하는지 보여주기 위해 답변을 업데이트하겠습니다 .
Max Vernon

1

방금이 특정 상황에서 문제가 발생했습니다. 공백이있는 모든 필드를 찾아서 청소해야했지만 데이터베이스 필드에서 4 가지 유형의 공백이 발견되었습니다 (ASCII 코드 테이블 참조).

  • 가로 탭 (char (9))
  • 줄 바꾸기 (char (10))
  • 세로 탭 (char (9))
  • 스페이스 (char (32))

이 쿼리가 도움이 될 수 있습니다.

UPDATE @TABLE SET @COLUMN = replace(replace(replace(replace(@COLUMN,CHAR(9),''),CHAR(10),''),CHAR(13),''),CHAR(32),'')

이것은 질문의 시작과 끝뿐만 아니라 필드 중간에서 공백을 제거합니다.
Colin 't Hart

네, 맞습니다, 편집
하겠습니다

-1

LTRIM / RTRIM은 공백 만 자르기 때문에 두 번째 예를 구문 분석해야합니다. 실제로 SQL에서 데이터로 간주하는 내용 (/ r, / t 등)을 잘라내려고합니다. 찾고있는 값을 알고 있으면 REPLACE를 사용하여 값을 바꾸십시오. 더 좋은 방법은 함수를 작성하여 호출하는 것입니다.


-1

원하는 경우 우아한 기능을 사용하십시오.

CREATE FUNCTION s_Trim
(
    @s nvarchar(max)
)
RETURNS nvarchar(max)
AS
BEGIN
    -- Create comparators for LIKE operator
    DECLARE @whitespaces nvarchar(50) = CONCAT('[ ', CHAR(9), CHAR(10), CHAR(13), ']'); -- Concat chars that you consider as whitespaces
    DECLARE @leftComparator nvarchar(50) = @whitespaces + '%',
            @rightComparator nvarchar(50) = '%' + @whitespaces;
    -- LTRIM
    WHILE @s LIKE @leftComparator AND LEN(@s + 'x') > 1 SET @s = RIGHT(@s, LEN(@s + 'x') - 2)
    -- RTRIM
    WHILE @s LIKE @rightComparator AND LEN(@s + 'x') > 1 SET @s = LEFT(@s, LEN(@s + 'x') - 2)

    RETURN @s;
END
GO

1
스칼라 가치있는 기능은 거의 우아하지 않습니다. 쿼리를 순차적으로 실행하고 행당 한 번만 실행합니다 (쿼리 당 한 번이 아님). 대신 인라인 테이블 값 함수를 살펴 봐야합니다.
Erik Darling

-2

대용량 데이터에서 기능을 사용하면 실행 시간이 오래 걸릴 수 있습니다. 8 백만 행의 데이터 세트가 있는데 함수를 사용하는 데 30 분 이상이 걸렸습니다. replace(replace(replace(replace(@COLUMN,CHAR(9),''),CHAR(10),''),CHAR(13),''),CHAR(32),'')5 초 밖에 걸리지 않았습니다. 모두 감사합니다. @ sami.almasagedi와 @Colin 't Hart가 see겠습니다.


반복하는 대답에서와 같이 첫 번째 공백 문자와 마지막 공백이 아닌 문자 사이의 공백을 유지 해야하는 경우 문제가 해결되지 않습니다. 속도는 원하는 답을 얻을 때만 유용합니다. 또한 함수가 이와 같은 쿼리 속도를 늦추지 않는 방법에 대해서는 허용 된 답변의 참고 사항을 참조하십시오.
RDFozz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.