2009-10-16 3 views
26

Это основано на такой же вопрос How to Replace Multiple Characters in Access SQL?Как заменить несколько символов в SQL?

Я написал это, так как SQL Server 2005, кажется, есть ограничение на замену() функции до 19 замен внутри где п.

У меня есть следующая задача: необходимо выполнить матч на колонке, а также улучшить шансы матча зачистки многожильных ненужных символов с помощью замены функции

DECLARE @es NVarChar(1) SET @es = '' 
DECLARE @p0 NVarChar(1) SET @p0 = '!' 
DECLARE @p1 NVarChar(1) SET @p1 = '@' 
---etc... 

SELECT * 
FROM t1,t2 
WHERE REPLACE(REPLACE(t1.stringkey,@p0, @es), @p1, @es) 
    = REPLACE(REPLACE(t2.stringkey,@p0, @es), @p1, @es)  
---etc 

() Если есть> 19 REPLACE() в этом разделе, это не работает. Таким образом, решение, которое я придумал, чтобы создать функцию SQL под названием trimChars в этом примере (простите их, начиная с @ 22

CREATE FUNCTION [trimChars] (
    @string varchar(max) 
) 

RETURNS varchar(max) 
AS 
BEGIN 

DECLARE @es NVarChar(1) SET @es = '' 
DECLARE @p22 NVarChar(1) SET @p22 = '^' 
DECLARE @p23 NVarChar(1) SET @p23 = '&' 
DECLARE @p24 NVarChar(1) SET @p24 = '*' 
DECLARE @p25 NVarChar(1) SET @p25 = '(' 
DECLARE @p26 NVarChar(1) SET @p26 = '_' 
DECLARE @p27 NVarChar(1) SET @p27 = ')' 
DECLARE @p28 NVarChar(1) SET @p28 = '`' 
DECLARE @p29 NVarChar(1) SET @p29 = '~' 
DECLARE @p30 NVarChar(1) SET @p30 = '{' 

DECLARE @p31 NVarChar(1) SET @p31 = '}' 
DECLARE @p32 NVarChar(1) SET @p32 = ' ' 
DECLARE @p33 NVarChar(1) SET @p33 = '[' 
DECLARE @p34 NVarChar(1) SET @p34 = '?' 
DECLARE @p35 NVarChar(1) SET @p35 = ']' 
DECLARE @p36 NVarChar(1) SET @p36 = '\' 
DECLARE @p37 NVarChar(1) SET @p37 = '|' 
DECLARE @p38 NVarChar(1) SET @p38 = '<' 
DECLARE @p39 NVarChar(1) SET @p39 = '>' 
DECLARE @p40 NVarChar(1) SET @p40 = '@' 
DECLARE @p41 NVarChar(1) SET @p41 = '-' 

return REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
     @string, @p22, @es), @p23, @es), @p24, @es), @p25, @es), @p26, @es), @p27, @es), @p28, @es), @p29, @es), @p30, @es), @p31, @es), @p32, @es), @p33, @es), @p34, @es), @p35, @es), @p36, @es), @p37, @es), @p38, @es), @p39, @es), @p40, @es), @p41, @es) 
END 

Это может быть использован в дополнение к другим заменить строки

SELECT * 
FROM t1,t2 
WHERE trimChars(REPLACE(REPLACE(t1.stringkey,@p0, @es), @p1, @es) 
     = REPLACE(REPLACE(t2.stringkey,@p0, @es), @p1, @es)) 

Я создал несколько функций, чтобы сделать аналогично замене как так trimChars (trimMoreChars (

SELECT * 
FROM t1,t2 
WHERE trimChars(trimMoreChars(REPLACE(REPLACE(t1.stringkey,@p0, @es), @p1, @es) 
     = REPLACE(REPLACE(t2.stringkey,@p0, @es), @p1, @es))) 

Может ли кто-нибудь дать мне лучшее решение этой проблемы с точки зрения производительности и, возможно, более чистой реализации?

+0

Можете ли вы дезинфицировать свой вход, прежде чем передавать его в базу данных? – Juliet

+1

Насколько велики таблицы t1 и t2? Можно ли выполнять работу за пределами базы данных? Похож на работу для регулярных выражений. –

ответ

20

Я бы рассмотрел making a CLR UDFinstead и использовал регулярные выражения (как строку, так и шаблон можно передать как параметры), чтобы выполнить полный поиск и заменить для диапазона символов. Он должен легко превзойти этот SQL UDF.

40

Один полезный трюк в SQL - это возможность использовать @var = function(...) для назначения значения. Если у вас есть несколько записей в вашем наборе записей, ваш вар назначаются несколько раз с побочными эффектами:

declare @badStrings table (item varchar(50)) 

INSERT INTO @badStrings(item) 
SELECT '>' UNION ALL 
SELECT '<' UNION ALL 
SELECT '(' UNION ALL 
SELECT ')' UNION ALL 
SELECT '!' UNION ALL 
SELECT '?' UNION ALL 
SELECT '@' 

declare @testString varchar(100), @newString varchar(100) 

set @teststring = 'Juliet ro><0zs my s0x()[email protected][email protected][email protected]!' 
set @newString = @testString 

SELECT @newString = Replace(@newString, item, '') FROM @badStrings 

select @newString -- returns 'Juliet ro0zs my s0xrzone' 
+0

Это очень здорово - как включить это внутри предложения where в моем вопросе выше? - спасибо – kiev

+0

@kiev: вы не можете поместить это в предложение WHERE. –

+2

@ kiev: создание пользовательской функции - правильный подход. Тем не менее, вам лучше использовать мой подход, вместо того, чтобы встраивать bajillion, заменяя друг друга, поскольку мой подход поддерживает неопределенное количество замещений. Вы можете сделать функцию более динамичной, перейдя в список строк, разделенных запятыми, для замены, используя функцию split (http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648), чтобы преобразовать список в таблицу, а затем возвращает замененную строку. – Juliet

0

Одним из вариантов является использование таблицы числа/индикаторной вести итерационный процесс с помощью запроса псевдо-набора на основе ,

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

create table charMap (srcChar char(1), replaceChar char(1)) 
insert charMap values ('a', 'z') 
insert charMap values ('b', 'y') 


create table testChar(srcChar char(1)) 
insert testChar values ('1') 
insert testChar values ('a') 
insert testChar values ('2') 
insert testChar values ('b') 

select 
coalesce(charMap.replaceChar, testChar.srcChar) as charData 
from testChar left join charMap on testChar.srcChar = charMap.srcChar 

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

create table tally (i int) 
declare @i int 
set @i = 1 
while @i <= 256 begin 
    insert tally values (@i) 
    set @i = @i + 1 
end 

create table testData (testString char(10)) 
insert testData values ('123a456') 
insert testData values ('123ab456') 
insert testData values ('123b456') 

select 
    i, 
    SUBSTRING(testString, i, 1) as srcChar, 
    coalesce(charMap.replaceChar, SUBSTRING(testString, i, 1)) as charData 
from testData cross join tally 
    left join charMap on SUBSTRING(testString, i, 1) = charMap.srcChar 
where i <= LEN(testString) 
0

Я не знаю, почему Чарльз Bretana удалил свой ответ, поэтому я добавляю его обратно в качестве CW ответа, но PERSISTED вычисляемого столбца является действительно хорошим способом справиться с этим случаями, когда вам нужно очищенные или преобразовать данные почти все время, но нужно сохранить оригинальный мусор. Его предложение является релевантным и соответствующим образом НЕПРАВИЛЬНО, как вы решаете очистить свои данные.

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

2

Предлагаю вам создать скалярную функцию, определенную пользователем. Это пример (извините заранее, так как имена переменных на испанском языке):

CREATE FUNCTION [dbo].[Udf_ReplaceChars] (
    @cadena VARCHAR(500), -- String to manipulate 
    @caracteresElim VARCHAR(100), -- String of characters to be replaced 
    @caracteresReem VARCHAR(100) -- String of characters for replacement 
) 
RETURNS VARCHAR(500) 
AS 
BEGIN 
    DECLARE @cadenaFinal VARCHAR(500), @longCad INT, @pos INT, @caracter CHAR(1), @posCarER INT; 
    SELECT 
    @cadenaFinal = '', 
    @longCad = LEN(@cadena), 
    @pos = 1; 

    IF LEN(@caracteresElim)<>LEN(@caracteresReem) 
    BEGIN 
     RETURN NULL; 
    END 

    WHILE @pos <= @longCad 
    BEGIN 
     SELECT 
     @caracter = SUBSTRING(@cadena,@pos,1), 
     @pos = @pos + 1, 
     @posCarER = CHARINDEX(@caracter,@caracteresElim); 

     IF @posCarER <= 0 
     BEGIN 
      SET @cadenaFinal = @cadenaFinal + @caracter; 
     END 
     ELSE 
     BEGIN 
      SET @cadenaFinal = @cadenaFinal + SUBSTRING(@caracteresReem,@posCarER,1) 
     END 
    END 

    RETURN @cadenaFinal; 
END 

Вот пример использования этой функции:

SELECT dbo.Udf_ReplaceChars('This is a test.','sat','Z47'); 

И результат: 7hiZ IZ 4 7eZ7 ,

Как вы можете видеть, каждый символ параметра @caracteresElim заменяется символом в том же положении из параметра @caracteresReem.

+0

выглядит как хорошее решение – kiev

-1

Вот шаги

  1. Создание функции CLR

Смотреть следующий код:

public partial class UserDefinedFunctions 
{ 

[Microsoft.SqlServer.Server.SqlFunction] 
public static SqlString Replace2(SqlString inputtext, SqlString filter,SqlString  replacewith) 
{ 

    string str = inputtext.ToString(); 
    try 
    { 
     string pattern = (string)filter; 
     string replacement = (string)replacewith; 
     Regex rgx = new Regex(pattern); 
     string result = rgx.Replace(str, replacement); 
     return (SqlString)result; 

    } 
    catch (Exception s) 
    { 
     return (SqlString)s.Message; 
    } 
} 
} 
  1. Развертывание функции CLR

  2. Теперь Проверьте это

Смотреть следующий код:

create table dbo.test(dummydata varchar(255)) 
Go 
INSERT INTO dbo.test values('[email protected]'),('This 12is @test') 
Go 
Update dbo.test 
set dummydata=dbo.Replace2(dummydata,'[[email protected]]','') 

select * from dbo.test 
dummydata, Psswrd, This is test booom!!!!!!!!!!!!! 
11

мне очень нравится @ решение Жюльетт в! Я бы просто использовать КТР, чтобы получить все недопустимые символы:

DECLARE @badStrings VARCHAR(100) 
DECLARE @teststring VARCHAR(100) 

SET @badStrings = '><()[email protected]' 
SET @teststring = 'Juliet ro><0zs my s0x()[email protected][email protected][email protected]!' 

;WITH CTE AS 
(
    SELECT SUBSTRING(@badStrings, 1, 1) AS [String], 1 AS [Start], 1 AS [Counter] 
    UNION ALL 
    SELECT SUBSTRING(@badStrings, [Start] + 1, 1) AS [String], [Start] + 1, [Counter] + 1 
    FROM CTE 
    WHERE [Counter] < LEN(@badStrings) 
) 

SELECT @teststring = REPLACE(@teststring, CTE.[String], '') FROM CTE 

SELECT @teststring 

Джульетта ro0zs мой s0xrzone

+0

Это решение сломало мой awesometer. Использует рекурсивный CTE, а затем рекурсивный REPLACE из @teststring ... – Baodad

+0

Это потрясающе.Будьте осторожны, потому что это не будет занимать конечное пространство в @badStrings. –

+0

Можно ли применить это решение к выбору таблицы? IE Выберите поле, в котором значение в ('1', '2') выберет поле '<>! 1' – Adam

1
declare @testVal varchar(20) 

set @testVal = '?t/es?ti/n*g 1*2?3*' 

select @testVal = REPLACE(@testVal, item, '') from (select '?' item union select '*' union select '/') list 

select @testVal; 
0

Хотя этот вопрос был задан вопрос о SQL Server 2005, то стоит отметить, что, как сервера Sql 2017, запрос может быть выполнен с помощью новой функции TRANSLATE.

https://docs.microsoft.com/en-us/sql/t-sql/functions/translate-transact-sql

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

Смежные вопросы