Иногда встаёт задача почистить строки от лишних символов. Если это 1-2 символа, то мы легко и не принуждённо воспользуемся функцией REPLACE, но при необходимости заменить большее количество символов, такое решение не будет изящным.
Вот примерно так выглядит множественный REPLACE. Согласитесь, данное решение совсем не читаемо.
SELECT F_C_DATA_GR.NDF_CODE, (replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace( replace(replace(replace(replace(replace(replace(f_c_data_gr.NAME + ISNULL(f_c_data_gr.FORM, '') + ISNULL(f_c_data_gr.MANUFACTURER, '') + CAST(F_C_DATA_GR.PRICE AS varchar(15)) , '.', ''), ',', ''), '_', ''), ' ', ''), ' ', ''), '|', ''), '№', 'N'), '-', ''), 'і', 'и'), '/', ''), '##', ''), '#', ''), '(', ''), ')', ''), '"', ''), '@', '') , '$', ''), '**', ''), '%', ''), '+', ''), '*', ''), '=', ''), '~', '')) n FROM F_C_DATA_GR
Тут нам на помощь могут придти следующие методы:
Метод 1 (функция):
Создаём функцию, куда будем передавать строку и необходимые символы для замены:
create function [dbo].[Split](@String varchar(8000), @Delimiter char(1)) returns @temptable TABLE (items varchar(8000)) as begin declare @idx int declare @slice varchar(8000) select @idx = 1 if len(@String)<1 or @String is null return while @idx!= 0 begin set @idx = charindex(@Delimiter,@String) if @idx!=0 set @slice = left(@String,@idx - 1) else set @slice = @String if(len(@slice)>0) insert into @temptable(Items) values(@slice) set @String = right(@String,len(@String) - @idx) if len(@String) = 0 break end return end
Вызываем функцию:
DECLARE @NEWSTRING VARCHAR(100) SET @NEWSTRING = '(N_100-(6858)*(6858)*N_100/0_2)%N_35' ; SELECT @NEWSTRING = REPLACE(@NEWSTRING, items, '~') FROM dbo.Split('+,-,*,/,%,(,)', ','); PRINT @NEWSTRING
На выходе будет следующее:
~N_100~~6858~~~6858~~N_100~0_2~~N_35
Вывод: Данный метод не самый лучший, так как имеет проблемы с производительностью и со встраиваемостью в запрос.
Метод 2 (функция, встраиваемая в запрос):
Создаём функцию:
CREATE FUNCTION StringReduce ( @inputstr VARCHAR(4096) , @stripchrs VARCHAR(255) ) RETURNS VARCHAR(4096) AS BEGIN DECLARE @charcounter INT SET @charcounter = 1 WHILE @charcounter <= LEN(@stripchrs) BEGIN SET @inputstr = REPLACE(@inputstr, SUBSTRING(@stripchrs, @charcounter, 1), '') SET @charcounter = @charcounter + 1 END RETURN @inputstr END
Создаём временную таблицу, напомняем её данными и встраиваем в запрос:
CREATE TABLE #ManyCharacters ( name nvarchar(255) ) INSERT INTO #ManyCharacters VALUES ('ABC!@#%DEFgh') INSERT INTO #ManyCharacters VALUES ('~!102WXY&*()_Z') SELECT dbo.StringReduce(name, '@#$^&*()-+_!%~') FROM #ManyCharacters DROP TABLE #ManyCharacters
Вывод: Данный метод уже можно использовать при выборке из таблицы, но в теории, скорость работы данного метода ещё не оптимальный
Метод 3 (CTE — обобщённое табличное выражение):
Создаём временную таблицу и заполняем её данными. Именно данная таблица будет использоваться в CTE:
CREATE TABLE #Foobar ( key_col INT PRIMARY KEY, text_col NVARCHAR(100)); INSERT INTO #Foobar VALUES (1, N'ABC!@#%DEFgh'); INSERT INTO #Foobar VALUES (2, N'~!102WXY&*()_Z');
Создаём CTE (в нашем случае мы заменяем символы на пустое место, можно заменять на любое значение, для этого необходимо немного модифицировать CTE):
WITH Clean (key_col, text_col, ch) AS (SELECT key_col, REPLACE(text_col, CHAR(255), ''), 255 FROM #Foobar UNION ALL SELECT key_col, CASE WHEN CHAR(ch - 1) NOT LIKE '[A-Z!]' THEN REPLACE(text_col, CHAR(ch - 1), '') ELSE text_col END, ch - 1 FROM Clean WHERE ch > 1)
Делаем выбоорку и удаляем временную таблицу:
SELECT key_col, text_col FROM Clean WHERE ch = 1 OPTION (MAXRECURSION 255); DROP TABLE #Foobar
Вывод: Данный метод, на мой взгляд, менее удобный, но подразумевается, что работает быстрее.
Метод 4 (dll):
Так же можно написать dll, подключить её и с помощью программирования обработать все необходимые символы.
Вывод: Данный метод будет максимально быстрым.
Более подробно про CTE (обобщённое табличное выражение)