Как написать рекурсивный запрос на замену TSQL?

#tsql #substring

#tsql #подстрока

Вопрос:

Я использую SSMS 2008 и пытаюсь написать оператор рекурсивной замены. У меня есть хорошее начало в этом, но оно еще не работает полностью. Я хочу заменить каждое вхождение тегов XML, встречающихся в одном столбце, пустой строкой. Итак, я хочу заменить весь диапазон от «<» до «>» для каждой записи. Вот что у меня есть:

 DECLARE @I INTEGER
SET @I = 3
while 
@I > 0
--(select [note_text] from #TEMP_PN where [note_text] LIKE '%<%') 
BEGIN
UPDATE #TEMP_PN 
SET [note_text] = replace([note_text],substring([note_text],CHARINDEX('<',[note_text]),CHARINDEX('>',[note_text])),'')
from #TEMP_PN
where [note_text] LIKE '%Microsoft-com%'
SET @I = @I - 1 
END

SELECT * FROM #TEMP_PN
 

Проблема с этим кодом в том, что я жестко запрограммировал @I равным 3. Однако я хочу, чтобы он продолжал заменять «<» на «>» пустой строкой для каждой записи, пока не останется символов «<«. Итак, я попробовал закомментированную строку выше, но это выдает ошибку более чем в одной записи / подзапросе. Как я могу добиться этой рекурсивной функциональности? Кроме того, мой оператор Replace выше заменил только символы «<» для некоторых записей, как ни странно.

Я попробовал ваш пример кода, но он по-прежнему не заменяет все экземпляры этого текста для каждой записи, а для некоторых записей он не заменяет никакого текста, хотя в этих записях есть «<«. Вот запись, в которой ваш скрипт не заменяет ни одной подстроки. Может быть, это проблема с особым символом?

 <DIV class=gc-message-sms-row><SPAN class=gc-message-sms-from>TLS: </SPAN><SPAN class=gc-message-sms-text>Hi Reggie... I'm on my way to Lynn.. see you soon</SPAN> <SPAN class=gc-message-sms-time>3:09 PM </SPAN></DIV>
 

Ответ №1:

Вы были довольно близки… проблема в том, что SUBSTRING третий параметр — это длина, а не позиция, на которой нужно остановиться.

 DECLARE @RowsUpdated INT
SET @RowsUpdated = 1
WHILE (@RowsUpdated > 0)
BEGIN
    UPDATE #TEMP_PN 
SET [note_text] = 
    REPLACE(
            [note_text], 
            substring(
                [note_text],
                CHARINDEX('<',[note_text]), 
                CHARINDEX(
                    '>',
                    SUBSTRING([note_text], CHARINDEX('<',[note_text]), 1   LEN([note_text]) - CHARINDEX('<',[note_text]))
                )
            ),
        '')
from #TEMP_PN
where [note_text] LIKE '%Microsoft-com%' and [note_text] like '%<%>%'

    SET @RowsUpdated = @@ROWCOUNT
END

SELECT * FROM #TEMP_PN
 

ВТОРОЕ РЕДАКТИРОВАНИЕ:

Хорошо, я обновил оба запроса; теперь этот код должен обрабатывать начало > перед первым тегом … что, я думаю, могло быть проблемой.

 DECLARE @TestString VARCHAR(MAX)
SELECT @TestString = '><DIV class=gc-message-sms-row><SPAN class=gc-message-sms-from>TLS: </SPAN><SPAN class=gc-message-sms-text>Hi Reggie... I''m on my way to Lynn.. see you soon</SPAN> <SPAN class=gc-message-sms-time>3:09 PM </SPAN></DIV>'

DECLARE @RowsUpdated INT
SET @RowsUpdated = 1

WHILE (@RowsUpdated > 0)
BEGIN

    SELECT
        @TestString = 
            REPLACE(
                @TestString, 
                substring(
                    @TestString,
                    CHARINDEX('<',@TestString), 
                    CHARINDEX(
                        '>',
                        SUBSTRING(@TestString, CHARINDEX('<',@TestString), 1   LEN(@TestString) - CHARINDEX('<',@TestString))
                    )
                ),
            '')
    WHERE @TestString LIKE '%<%>%'

    SET @RowsUpdated = @@ROWCOUNT
END

SELECT @TestString
 

Может быть, это потому, что эта заметка не соответствует [note_text] LIKE '%Microsoft-com%' критериям?

Комментарии:

1. На самом деле, похоже, у меня все еще есть проблема. Ваш код работает для большинства записей. Однако я только что получил сообщение об ошибке: «Недопустимый параметр длины, переданный функции LEFT или SUBSTRING. Оператор был завершен «.

2. Ах, я думаю, я знаю, когда это может произойти… это происходило бы в случаях, когда строка была чем-то вроде «> бла-бла-бла <тег>», поэтому в этом случае она по-прежнему соответствует критериям like, потому что есть тег, но терпит неудачу, потому что длина становится отрицательной, потому что> предшествует < …. Позвольте мне посмотреть, смогу ли я это исправить…

3. Потрясающе! Кажется, это работает для меня. Единственная проблема сейчас заключается в том, что для запуска требуется некоторое время, поскольку он должен сделать это для 90 000 записей!