SQL 바꾸기 함수 내부의 정규식 패턴?


82
SELECT REPLACE('<strong>100</strong><b>.00 GB', '%^(^-?\d*\.{0,1}\d+$)%', '');

숫자의 두 부분 사이에있는 마크 업을 위의 정규식으로 바꾸고 싶지만 작동하지 않는 것 같습니다. 나는 '%[^0-9]%'단지 테스트 와 같은 더 간단한 것을 시도했지만 작동하지 않았기 때문에 잘못된 정규식 구문인지 확실 하지 않습니다. 누구든지 내가 이것을 어떻게 얻을 수 있는지 알고 있습니까?


3
답변을 다시 검토 할 수 있습니다.
Mukus 2014

1
최종 결과는 무엇입니까? 100.00또는 기대 100.00 GB합니까? 마크 업 패턴에 맞지 않는 서식이 지정된 숫자의 다른 예가 소수점 왼쪽 부분에만 있는가? 마크 업은 100<i>.00</i> GB? 오른쪽에 항상 2 자리 통화 코드가 있습니까?
Solomon Rutzky

@srutzky 모든 값이있는 경우 소수점이있는 숫자를 원합니다. 또한 모든 값이있는 것은 아닙니다. 또한 생성 되었기 때문에 사실상 패턴이 없지만 타사 HTML 생성기가 있습니다. 때로는 통화가 숫자 뒤에 가끔씩 앞에 있고, 때로는 기호-$, 때로는 코드-USD, 공백없이-없음 등이 있습니다. 단순히 매우 쓰레기 데이터
JanT

답변:


62

PATINDEX 를 사용 하여 패턴 (문자열) 발생의 첫 번째 인덱스를 찾을 수 있습니다 . 그런 다음 STUFF 를 사용 하여 일치하는 패턴 (문자열)에 다른 문자열을 채 웁니다.

각 행을 반복합니다. 각 잘못된 문자를 원하는 문자로 바꿉니다. 귀하의 경우에는 숫자가 아닌 것을 공백으로 바꾸십시오. 내부 루프는 현재 셀에 루프의 잘못된 문자가 둘 이상있는 경우입니다.

DECLARE @counter int

SET @counter = 0

WHILE(@counter < (SELECT MAX(ID_COLUMN) FROM Table))
BEGIN  

    WHILE 1 = 1
    BEGIN
        DECLARE @RetVal varchar(50)

        SET @RetVal =  (SELECT Column = STUFF(Column, PATINDEX('%[^0-9.]%', Column),1, '')
        FROM Table
        WHERE ID_COLUMN = @counter)

        IF(@RetVal IS NOT NULL)       
          UPDATE Table SET
          Column = @RetVal
          WHERE ID_COLUMN = @counter
        ELSE
            break
    END

    SET @counter = @counter + 1
END

주의 : 이것은 느립니다! varchar 열이 있으면 영향을 미칠 수 있습니다. 따라서 LTRIM RTRIM을 사용하면 도움이 될 수 있습니다. 어쨌든 느립니다.

신용은 이것에 간다 StackOverFlow 답변에 .

편집 크레딧도 @srutzky로 이동합니다.

Edit (by @Tmdean) 한 번에 한 행을 수행하는 대신이 답변을보다 집합 기반 솔루션에 적용 할 수 있습니다. 여전히 단일 행에서 숫자가 아닌 문자 수의 최대 값을 반복하므로 이상적이지는 않지만 대부분의 상황에서 허용되어야한다고 생각합니다.

WHILE 1 = 1 BEGIN
    WITH q AS
        (SELECT ID_Column, PATINDEX('%[^0-9.]%', Column) AS n
        FROM Table)
    UPDATE Table
    SET Column = STUFF(Column, q.n, 1, '')
    FROM q
    WHERE Table.ID_Column = q.ID_Column AND q.n != 0;

    IF @@ROWCOUNT = 0 BREAK;
END;

필드가 아직 스크러빙되었는지 여부를 나타내는 테이블의 비트 열을 유지하면 효율성을 상당히 향상시킬 수도 있습니다. (NULL은 내 예에서 "알 수 없음"을 나타내며 열 기본값이어야합니다.)

DECLARE @done bit = 0;
WHILE @done = 0 BEGIN
    WITH q AS
        (SELECT ID_Column, PATINDEX('%[^0-9.]%', Column) AS n
        FROM Table
        WHERE COALESCE(Scrubbed_Column, 0) = 0)
    UPDATE Table
    SET Column = STUFF(Column, q.n, 1, ''),
        Scrubbed_Column = 0
    FROM q
    WHERE Table.ID_Column = q.ID_Column AND q.n != 0;

    IF @@ROWCOUNT = 0 SET @done = 1;

    -- if Scrubbed_Column is still NULL, then the PATINDEX
    -- must have given 0
    UPDATE table
    SET Scrubbed_Column = CASE
        WHEN Scrubbed_Column IS NULL THEN 1
        ELSE NULLIF(Scrubbed_Column, 0)
    END;
END;

스키마를 변경하지 않으려면 마지막에 실제 테이블에 적용되는 테이블 값 변수에 중간 결과를 저장하도록 쉽게 조정할 수 있습니다.


2
이 솔루션이 작동하려면 최소한 PATINDEX 패턴에 마침표를 추가해야합니다. 이어야합니다 [^0-9.]. 경우에 당신은 소수점을 제거하고 있어야한다 무엇 켜지지 100.0010000.
Solomon Rutzky

@srutzky ok는 '.'를 추가했습니다. 저는 실제로 알파벳이 아닌 작업을하고 있었고 ^ 0-9를하면 효과가있을 것이라고 생각했습니다.
Mukus 2014

노력에 +1하지만 (또한 지적했듯이) 보고서 실행 시간이 너무 길어지고 속도가 느리지 만 데이터가 작은 경우에는 훌륭한 솔루션입니다!
JanT 2014 년

1
방금 이와 비슷한 작업을했기 때문에 더 빠른 솔루션으로 답변을 업데이트하겠습니다. 여전히 이상적이지는 않지만 대부분의 상황에서 성능이 허용됩니다.
Tmdean 2015-06-30

@Tmdean : 이것에 기여 해주셔서 감사합니다. 다음에 비슷한 문제가 생기면 시도해 봅니다.
JanT

23

발견 된 캐릭터를 유일한 위치로 제거하는 대신 사용하는 Replace(Column, BadFoundCharacter, '')것이 훨씬 더 빠를 수 있습니다. 또한 각 열에서 다음에 발견 된 하나의 잘못된 문자를 대체하는 대신 발견 된 모든 문자를 대체합니다.

WHILE 1 = 1 BEGIN
    UPDATE dbo.YourTable
    SET Column = Replace(Column, Substring(Column, PatIndex('%[^0-9.-]%', Column), 1), '')
    WHERE Column LIKE '%[^0-9.-]%'
    If @@RowCount = 0 BREAK;
END;

나는 이것이 더 적은 작업을 수행하기 때문에 허용되는 대답보다 더 잘 작동한다고 확신합니다. 더 빠를 수있는 다른 방법도 있지만 지금은 탐색 할 시간이 없습니다.


재미있어 보이지만 지금은 시도 할 시간이 없지만 시간이 있으면 할 것입니다. 건배
JanT

4
이것은 다소 관련이없는 문제에 도움이되었습니다. Replace(Column, Substring(Column, PatIndex('%[^0-9.-]%', Column), 1), '')선택 쿼리에서 귀하의 비트를 사용했습니다 . 감사합니다!
jyoseph

1
트윗 담아 가기 이렇게하면 특정 불량 문자의 모든 인스턴스 만 제거되고 불량 문자 집합이 1보다 큰 경우 반복적으로 실행해야합니다.
ErikE

@ErikE 헤드 업 주셔서 감사합니다! 숫자가 아닌 항목을 제거하기 위해 전화 번호가있는 열 (패턴을 % [^ 0-9] %로 약간 수정)을 쿼리하는 데 사용했습니다. 따라서 사용자는 333-1234를 쿼리 할 수 ​​있고 3331234로 입력 된 전화 번호와 일치 할 것입니다. 내가 올바르게 이해했다면 전화 번호가 (333) -333-1234 인 경우 첫 번째 ? "("나는 시험해야하는 좀 더.
jyoseph

옳은. CLR 모듈을 설치할 수 있습니다. 또는 이상적으로는 프로그램 코드에서 수행하십시오.
ErikE

23

일반적으로 SQL Server는 정규식을 지원하지 않으며 네이티브 T-SQL 코드에서 사용할 수 없습니다.

이를 위해 CLR 함수를 작성할 수 있습니다. 예를 들어 여기를 참조 하십시오 .


1
좋아요, 그게 유일한 방법 인 것 같습니다 ... 감사합니다
JanT

4

나는이 게시물을 우연히 발견하여 다른 것을 찾고 있었지만 훨씬 더 효율적인 솔루션을 언급하고 있다고 생각했습니다. 세트 기반 쿼리와 함께 사용할 때 실제로 모든 기능의 기본 구현이어야합니다. 교차 적용을 사용하는 것입니다. 테이블 기능. 주제가 여전히 활성 상태이므로 누군가에게 유용하기를 바랍니다.

임의의 newid에서 문자를 제거하는 1m 행 테스트 세트를 기반으로 한 재귀 집합 기반 쿼리 또는 스칼라 함수 실행을 기반으로 지금까지 몇 가지 답변에 대한 예제 런타임은 WHILE 루프 예제의 경우 34 초에서 2 분 5 초, 1m3에서 { forever}를 참조하세요.

교차 적용과 함께 테이블 함수를 사용하면 10 초 내에 동일한 목표를 달성합니다 . 처리하는 최대 길이와 같은 필요에 맞게 조정해야 할 수도 있습니다.

함수:

CREATE FUNCTION [dbo].[RemoveChars](@InputUnit VARCHAR(40))
RETURNS TABLE
AS
RETURN
    (
        WITH Numbers_prep(Number) AS
            (
                SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
            )
        ,Numbers(Number) AS
            (
                SELECT TOP (ISNULL(LEN(@InputUnit),0))
                    row_number() OVER (ORDER BY (SELECT NULL))
                FROM Numbers_prep a
                    CROSS JOIN Numbers_prep b
            )
        SELECT
            OutputUnit
        FROM
            (
                SELECT
                    substring(@InputUnit,Number,1)
                FROM  Numbers
                WHERE substring(@InputUnit,Number,1) like '%[0-9]%'
                ORDER BY Number
                FOR XML PATH('')
            ) Sub(OutputUnit)
    )

용법:

UPDATE t
SET column = o.OutputUnit
FROM ##t t
CROSS APPLY [dbo].[RemoveChars](t.column) o

4

다음은 이전 답변을 기반으로 이것을 수행하기 위해 작성한 함수입니다.

CREATE FUNCTION dbo.RepetitiveReplace
(
    @P_String VARCHAR(MAX),
    @P_Pattern VARCHAR(MAX),
    @P_ReplaceString VARCHAR(MAX),
    @P_ReplaceLength INT = 1
)
RETURNS VARCHAR(MAX)
BEGIN
    DECLARE @Index INT;

    -- Get starting point of pattern
    SET @Index = PATINDEX(@P_Pattern, @P_String);

    while @Index > 0
    begin
        --replace matching charactger at index
        SET @P_String = STUFF(@P_String, PATINDEX(@P_Pattern, @P_String), @P_ReplaceLength, @P_ReplaceString);
        SET @Index = PATINDEX(@P_Pattern, @P_String);
    end

    RETURN @P_String;
END;

요점

편집하다:

원래는 32 중첩 수준 제한이 있기 때문에 SQL 서버에서 잘 작동하지 않는 재귀 함수가있어 함수로 32 개 이상의 교체를 시도 할 때마다 아래와 같은 오류가 발생합니다. 더 많은 중첩을 허용하기 위해 서버 수준 변경을 시도하는 대신 (종료하지 않는 루프를 허용하는 것과 같이 위험 할 수 있음) while 루프로 전환하는 것이 훨씬 더 합리적입니다.

최대 저장 프로 시저, 함수, 트리거 또는 뷰 중첩 수준이 초과되었습니다 (제한 32).


2

솔루션을 재사용하려는 경우 SQL 함수 내에서 솔루션을 래핑하는 것이 유용 할 수 있습니다. 나는 심지어 세포 수준에서 그것을하고 있기 때문에 이것을 다른 대답으로 두는 것입니다.

CREATE FUNCTION [dbo].[fnReplaceInvalidChars] (@string VARCHAR(300))
RETURNS VARCHAR(300)
BEGIN
    DECLARE @str VARCHAR(300) = @string;
    DECLARE @Pattern VARCHAR (20) = '%[^a-zA-Z0-9]%';
    DECLARE @Len INT;
    SELECT @Len = LEN(@String); 
    WHILE @Len > 0 
    BEGIN
        SET @Len = @Len - 1;
        IF (PATINDEX(@Pattern,@str) > 0)
            BEGIN
                SELECT @str = STUFF(@str, PATINDEX(@Pattern,@str),1,'');    
            END
        ELSE
        BEGIN
            BREAK;
        END
    END     
    RETURN @str
END

2

시간 필드에 숫자가 아닌 문자가 포함 된 문자열을 정리하기 위해이 함수를 만들었습니다. 시간에는 분을 추가하지 않았을 때 물음표가 포함되어 있습니다 (예 : 20 : ??). 함수는 각 문자를 반복하고? 0 :

 CREATE FUNCTION [dbo].[CleanTime]
(
    -- Add the parameters for the function here
    @intime nvarchar(10) 
)
RETURNS nvarchar(5)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar nvarchar(5)
    DECLARE @char char(1)
    -- Add the T-SQL statements to compute the return value here
    DECLARE @i int = 1
    WHILE @i <= LEN(@intime)
    BEGIN
    SELECT @char =  CASE WHEN substring(@intime,@i,1) like '%[0-9:]%' THEN substring(@intime,@i,1) ELSE '0' END
    SELECT @ResultVar = concat(@ResultVar,@char)   
    set @i  = @i + 1       
    END;
    -- Return the result of the function
    RETURN @ResultVar

END

2

성능이 뛰어나고 쉬운 솔루션을 찾고 있으며 CLR을 사용하려는 경우 :

create database TestSQLFunctions
go
use TestSQLFunctions
go
alter database TestSQLFunctions set trustworthy on

EXEC sp_configure 'clr enabled', 1
RECONFIGURE WITH OVERRIDE
go

CREATE ASSEMBLY [SQLFunctions]
AUTHORIZATION [dbo]
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C0103004BE8B85F0000000000000000E00022200B013000000800000006000000000000C2270000002000000040000000000010002000000002000004000000000000000600000000000000008000000002000000000000030060850000100000100000000010000010000000000000100000000000000000000000702700004F000000004000009803000000000000000000000000000000000000006000000C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000C8070000002000000008000000020000000000000000000000000000200000602E72737263000000980300000040000000040000000A0000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000000E00000000000000000000000000004000004200000000000000000000000000000000A4270000000000004800000002000500682000000807000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003A022D02022A020304281000000A2A1E02281100000A2A0042534A4201000100000000000C00000076342E302E33303331390000000005006C00000018020000237E000084020000CC02000023537472696E6773000000005005000004000000235553005405000010000000234755494400000064050000A401000023426C6F620000000000000002000001471500000900000000FA0133001600000100000013000000020000000200000003000000110000000F00000001000000030000000000CA01010000000000060025014F02060092014F02060044001D020F006F02000006006C00E20106000801E2010600D400E20106007901E20106004501E20106005E01E20106008300E2010600580030020600360030020600B700E20106009E00B0010600AA02DB010A00F300FC010A001F00FC010E00C3027E02000000000100000000000100010001001000C3029D0241000100010050200000000096002E001A0001005F2000000000861817020600040000000100BD0200000200F40100000300B102090017020100110017020600190017020A0029001702100031001702100039001702100041001702100049001702100051001702100059001702100061001702150069001702100071001702100079001702100089001702060099002E001A0081001702060020007B0010012E000B002A002E00130033002E001B0052002E0023005B002E002B006D002E0033006D002E003B006D002E0043005B002E004B0073002E0053006D002E005B006D002E0063008B002E006B00B5002E007300C2000480000001000000000000000000000000009D020000040000000000000000000000210016000000000004000000000000000000000021000A00000000000400000000000000000000002100DB010000000000000000003C4D6F64756C653E0053797374656D2E44617461006D73636F726C696200446174614163636573734B696E64005265706C61636500477569644174747269627574650044656275676761626C6541747472696275746500436F6D56697369626C6541747472696275746500417373656D626C795469746C6541747472696275746500417373656D626C7954726164656D61726B417474726962757465005461726765744672616D65776F726B41747472696275746500417373656D626C7946696C6556657273696F6E41747472696275746500417373656D626C79436F6E66696775726174696F6E4174747269627574650053716C46756E6374696F6E41747472696275746500417373656D626C794465736372697074696F6E41747472696275746500436F6D70696C6174696F6E52656C61786174696F6E7341747472696275746500417373656D626C7950726F6475637441747472696275746500417373656D626C79436F7079726967687441747472696275746500417373656D626C79436F6D70616E794174747269627574650052756E74696D65436F6D7061746962696C6974794174747269627574650053797374656D2E52756E74696D652E56657273696F6E696E670053514C46756E6374696F6E732E646C6C0053797374656D0053797374656D2E5265666C656374696F6E007061747465726E004D6963726F736F66742E53716C5365727665722E536572766572002E63746F720053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652E496E7465726F7053657276696365730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F6465730053797374656D2E546578742E526567756C617245787072657373696F6E730053514C46756E6374696F6E73004F626A656374007265706C6163656D656E7400696E70757400526567657800000000000000003A1617E607071B47B964858BCD87458B00042001010803200001052001011111042001010E04200101020600030E0E0E0E08B77A5C561934E0890801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F7773010801000200000000001101000C53514C46756E6374696F6E73000005010000000017010012436F7079726967687420C2A920203230323000002901002434346436386231632D393735312D343938612D396665352D32316666333934303738303900000C010007312E302E302E3000004D01001C2E4E45544672616D65776F726B2C56657273696F6E3D76342E352E320100540E144672616D65776F726B446973706C61794E616D65142E4E4554204672616D65776F726B20342E352E32808F010001005455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A4461746141636365737301000000000000982700000000000000000000B2270000002000000000000000000000000000000000000000000000A4270000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF25002000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001000000018000080000000000000000000000000000001000100000030000080000000000000000000000000000001000000000048000000584000003C03000000000000000000003C0334000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000001000000000000000100000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B0049C020000010053007400720069006E006700460069006C00650049006E0066006F0000007802000001003000300030003000300034006200300000001A000100010043006F006D006D0065006E007400730000000000000022000100010043006F006D00700061006E0079004E0061006D006500000000000000000042000D000100460069006C0065004400650073006300720069007000740069006F006E0000000000530051004C00460075006E006300740069006F006E00730000000000300008000100460069006C006500560065007200730069006F006E000000000031002E0030002E0030002E003000000042001100010049006E007400650072006E0061006C004E0061006D0065000000530051004C00460075006E006300740069006F006E0073002E0064006C006C00000000004800120001004C006500670061006C0043006F007000790072006900670068007400000043006F0070007900720069006700680074002000A90020002000320030003200300000002A00010001004C006500670061006C00540072006100640065006D00610072006B00730000000000000000004A00110001004F0072006900670069006E0061006C00460069006C0065006E0061006D0065000000530051004C00460075006E006300740069006F006E0073002E0064006C006C00000000003A000D000100500072006F0064007500630074004E0061006D00650000000000530051004C00460075006E006300740069006F006E00730000000000340008000100500072006F006400750063007400560065007200730069006F006E00000031002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E0030002E0030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C000000C43700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
WITH PERMISSION_SET = SAFE

go

CREATE FUNCTION RegexReplace(
    @input nvarchar(max),
    @pattern nvarchar(max),
    @replacement nvarchar(max)
) RETURNS nvarchar  (max)
AS EXTERNAL NAME SQLFunctions.[SQLFunctions.Regex].Replace; 

go

-- outputs This is a test 
select dbo.RegexReplace('This is a test 12345','[0-9]','')

DLL의 내용 : 여기에 이미지 설명 입력


1

저장 프로 시저로 들어오는 매개 변수에 대해서만이 작업을 수행하는 경우 다음을 사용할 수 있습니다.

declare @badIndex int
set @badIndex = PatIndex('%[^0-9]%', @Param)
while @badIndex > 0
    set @Param = Replace(@Param, Substring(@Param, @badIndex, 1), '')
    set @badIndex = PatIndex('%[^0-9]%', @Param)

0

더 간단하고 빠른 접근 방법은 알파벳의 각 문자를 반복하는 것입니다.

DECLARE @i int
SET @i = 0

WHILE(@i < 256)
BEGIN  

    IF char(@i) NOT IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.')      

      UPDATE Table SET Column = replace(Column, char(@i), '')

    SET @i = @i + 1

END

1
프로덕션에서 이와 같은 것을 사용하지 마십시오. where 절없이 245 개의 업데이트를 수행하고 있습니다. 작동하지만 효율적인 접근 방식과는 거리가 멀다. 더 나은 아이디어는 알파벳에서 사용 가능한 모든 문자 대신 제거하려는 문자를 반복하는 것입니다. 그러나 그것조차 더 나은 것으로 개선 될 수 있습니다.
Anderson Silva
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.