Шаблон регулярных выражений внутри функции замены SQL?



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


Я хочу заменить любую разметку между двумя частями числа С выше регулярным выражением, но это, кажется, не работает. Я не уверен, что это синтаксис регулярных выражений, потому что я попробовал более простой, такой как '%[^0-9]%' просто проверить, но это тоже не сработало. Кто-нибудь знает, как я могу этого достичь?

487   8  

8 ответов:

можно использовать PATINDEX чтобы найти первый индекс вхождения шаблона (строки). Тогда используйте материал чтобы вставить другую строку в шаблон (строку) соответствует.

цикл через каждую строку. Заменить все недопустимые символы с тем, что вы хотите. В вашем случае замените не числовой на пустой. Внутренний цикл-это если у вас есть более одного незаконного символа в текущей ячейке цикла.

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;

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

В общем смысле SQL Server не поддерживает регулярные выражения, и вы не можете использовать их в собственном коде T-SQL.

для этого можно написать функцию CLR. Смотрите здесь, например.

вместо удаления найденного символа по его единственной позиции, используя 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;

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

вот рекурсивная функция, которую я написал, чтобы выполнить это на основе предыдущих ответов.

CREATE FUNCTION dbo.RecursiveReplace
(
    @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);

    IF @Index > 0
    BEGIN
        -- Perform the replace
        SET @P_String = STUFF(@P_String, PATINDEX(@P_Pattern, @P_String), @P_ReplaceLength, @P_ReplaceString);

        -- Recurse
        SET @P_String = dbo.RecursiveReplace(@P_String, @P_Pattern, @P_ReplaceString, @P_ReplaceLength);
    END;

    RETURN @P_String;
END;

суть

обертывание решения внутри функции 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

Если вы делаете это только для параметра, поступающего в хранимую процедуру, вы можете использовать следующее:

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

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

пример выполнения на несколько ответов до сих пор на основе выполнения рекурсивных запросов на основе набора или скалярной функции, основанной на 1m тестовый набор строк, удаляющий символы из случайного newid, колеблется от 34s до 2m05s для примеров цикла WHILE и от 1m3s до {forever} для примеров функций.

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

функция:

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

Я думаю, что более простой и быстрый подход повторяется каждым символом алфавита:

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

Comments

    Ничего не найдено.