#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 записей!