열의 특수 문자를 공백으로 바꿉니다.


10

특수 문자를 공백으로 바꾸는 쿼리를 작성하려고합니다. 아래 코드는 행을 식별하는 데 도움이됩니다. (영숫자, 쉼표 및 공백이 유효합니다) :

SELECT columnA
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'

결과 집합에서 영숫자, 쉼표 및 공백 이외의 모든 문자가 ''(공백)으로 대체되도록 replace 함수를 select 문에 통합하는 방법은 무엇입니까? 이것은 작동하지 않습니다 :

SELECT replace(columnA,'%[^a-Z0-9, ]%',' ')
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'

답변:


11

26 개의 미국 영어 알파벳 문자 (대문자 및 소문자 버전) 만 사용하는 것이 확실하다면 다음 과 같이 간단한 범위 표기법을 사용 LIKE하거나 사용 하지 않아도됩니다. 대소 문자를 구분하지 않는 데이터 정렬을 사용할 때는 대문자 "Z"를 사용해야합니다.PATINDEX[a-z]

그러나 en-US 알파벳에는 없지만 문자에 대한 다양한 코드 페이지 / 데이터 정렬에서 사용할 수있는 문자를 얻을 수있는 경우 VARCHAR(예 Þ: 라틴어 대문자 "Thorn"= SELECT CHAR(0xDE)) 문자 클래스에 해당 문자를 포함해야합니다 [a-z0-9, Þ]. 물론 이러한 추가 문자는 코드 페이지별로 있습니다.

또한 데이터 정렬 유형 (SQL Server와 Windows) 및 민감도 설정 (대소 문자, 악센트 등의 민감도 대 비 민감성)이 특정 범위에 포함되는 문자에 영향을 미칩니다. 예를 들어, SQL Server 데이터 정렬은 대문자와 소문자를 Windows 데이터 정렬과 반대 순서로 정렬합니다. 즉, 두 유형의 데이터 정렬 모두에 대해 대소 문자를 구분하는 데이터 정렬을 가정하면 하나는 수행 AaBb...하고 다른 하나는 수행 aAbB...합니다. 그 결과는 그들 중 하나의 a범위 내에 A-Z있지만 다른 하나에는 해당되지 않습니다. 값 이 65이고 주어진 범위는 a-Z이진 데이터 정렬의 문자와 일치하지 않습니다 ( _BIN또는로 끝나 거나 _BIN2사용하지 않는 문자 _BIN).Aa는 97이므로 유효하지 않은 범위는 97에서 65입니다. ;-). 여기에 예제를 제공하기에는 너무 많은 변형이 있으므로 언젠가 내 블로그에 자세한 설명을 게시하려고 시도하고 링크를 통해이를 업데이트 할 것입니다. 그러나 미국 영어 문자 만 허용해야하는 경우 (다른 언어에서 유효한 문자를받을 수있는 경우에도) 다음과 같은 패턴 데이터 정렬 을 사용하는 것이 가장 좋습니다 .

LIKE '%[^A-Za-z0-9, ]%' COLLATE Latin1_General_100_BIN2

이제 NVARCHAR데이터 를 지원 하고 다양한 언어에서 "단어"문자를 얻을 수 있다면 T-SQL은 이러한 점을 구분할 수있는 실질적인 방법이 없기 때문에 큰 도움이되지 않습니다. 이 경우 정규식 (RegEx) (특히 Replace메소드 / 함수 )을 사용해야하며 SQLCLR을 통해서만 사용할 수 있습니다. 다음은 여러 개의 "특수"문자를 바꾸고 하나 이상의 언어로 유효한 문자를 모두 남기는 예를 보여줍니다.

DECLARE @Test NVARCHAR(500);
SET @Test = N'this$is%a<>TEST,;to}⌡↕strip╞╟╚══¶out_ç_ƒ▀ special-ij-೫-chars-舛-დ-א-B';
SELECT SQL#.RegEx_Replace4k(@Test, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL); 

보고:

this is a  TEST, to   strip      out ç ƒ  special ij ೫ chars 舛 დ א B

RegEx 표현식은 다음을 의미합니다.

  • \W= "단어가 아닌 문자"를 의미하는 RegEx "탈출 "
  • \p{Pc}= "Punctuation, Connector"의 유니 코드 "범주"(이 범주는 \W이스케이프에 의해 특별히 제외되기 때문에 일치에만 필요함 )
  • -[,]= 클래스 빼기 (쉼표가 \W이스케이프에 포함되므로 "특수"로 일치하지 않도록 제외해야 함 )

다음을 발행하여 간단히 테이블 업데이트를 수행 할 수 있습니다.

UPDATE tbl
SET    tbl.field = SQL#.RegEx_Replace4k(tbl.field, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL)
FROM   tbl
WHERE  SQL#.RegEx_IsMatch4k(tbl.field, N'[\W\p{Pc}-[,]]', 1, NULL) = 1;

이 예제에서는 SQLCLR 함수 의 무료 버전 SQL # 라이브러리 에서 사용할 수있는 두 가지 함수를 사용했습니다.이 함수는 다시 작성했지만 무료입니다. 또한 매개 변수 유형 NVARCHAR(4000)대신 사용으로 인해 더 빠른 "4k"버전을 사용 했습니다 NVARCHAR(MAX). 데이터가를 사용 NVARCHAR(MAX)하는 경우 함수 이름에서 "4k"를 제거하십시오.

참조 :


5

나는 비슷한 것을 하는 게시물을 여기에 가지고있다 .

기본적으로 재귀 적 CTE를 사용하여 한 번에 하나의 "나쁜"문자를 반복해서 반복하고 있습니다. STUFF를 사용하여 1 문자를 제거하고 (공백으로 바꿀 수는 있지만) PATINDEX를 사용하여 제거하려는 문자의 위치를 ​​찾습니다. 찾고있는 것을하기 위해 약간 수정할 수 있습니다. 그러나 "양호한"목록을 작성하지만 실제로는 기존 목록을 업데이트하지 않습니다.

DECLARE @Pattern varchar(50) = '%[^A-Za-z0-9, ]%';

WITH FixBadChars AS (SELECT StringToFix, StringToFix AS FixedString, 1 AS MyCounter, Id
                FROM BadStringList
                UNION ALL
                SELECT StringToFix, Stuff(FixedString, PatIndex(@Pattern, 
                    FixedString COLLATE Latin1_General_BIN2), 1, ' ') AS FixedString, 
                    MyCounter + 1, Id
                FROM FixBadChars
                WHERE FixedString COLLATE Latin1_General_BIN2 LIKE @Pattern)
SELECT StringToFix, FixedString, MyCounter, Id
FROM FixBadChars
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

쿼리가 아닌 업데이트를 수행하도록 하단 부분을 수정할 수 있어야하지만 실제로 시도하지는 않았습니다. 나는 이것이 다음과 같이 보일 것이라고 확신합니다.

UPDATE FixBadChars
SET StringToFix = FixedString
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

확장성에 관해서는 30 초 안에 ~ 170k 개의 청소 행을 반환했습니다. 다시 업데이트에 대해 확실하지 않지만 이것은 6 기가 바이트 램으로 상당히 느린 내 노트북에있었습니다.


0
Declare @String nchar(2000)='hg$%^AB,.:23ab-=+'

Declare @NewString VARCHAR(2000)=''
Declare @Lenght int=LEN(@String)
Declare @Index int=1

WHILE (@Index <= @Lenght)
BEGIN
    Declare @Letter nchar(1)=Substring(@String,@Index,1);
    Declare @ASCII int=ASCII(@Letter);
    If((@ASCII >= 48 and @ASCII <= 57) or (@ASCII >= 97 and @ASCII <= 122) or (@ASCII >= 65 and @ASCII <= 90))
    BEGIN
        SET @NewString += @Letter
    END
    ELSE
    BEGIN
        SET @NewString += ' '
    END
    SET @Index+=1

END
Select @NewString
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.