Шаблон регулярных выражений внутри функции замены SQL?
SELECT REPLACE('<strong>100</strong><b>.00 GB', '%^(^-?d*.{0,1}d+$)%', '');
Я хочу заменить любую разметку между двумя частями числа С выше регулярным выражением, но это, кажется, не работает. Я не уверен, что это синтаксис регулярных выражений, потому что я попробовал более простой, такой как '%[^0-9]%' просто проверить, но это тоже не сработало. Кто-нибудь знает, как я могу этого достичь?
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