2012-09-10 76 views
1

我有一个表“tblRandomString”与下面的数据:多替换在SQL Server 2005

ID ItemValue 

1 *Test" 
2 ?Test* 

我有另一个表“tblSearchCharReplacement”与下面的数据

Original Replacement 

*   `star` 
?   `quest` 
"   `quot` 
;   `semi` 

现在,我想使用这些替换在ItemValues中进行替换。 我尝试这样做:

Update T1 
SET ItemValue = select REPLACE(ItemValue,[Original],[Replacement]) 
FROM dbo.tblRandomString T1 
JOIN 
dbo.tblSpecialCharReplacement T2 
ON T2.Original IN ('"',';','*','?') 

但它不帮我,因为只有一个替换每次更新完成。

一个解决方案是我必须使用CTE来执行多个替换,如果它们存在。

有没有更简单的方法?

+1

其实,所有的更新换代确实是会发生 - 所有4个可能的结果计算,并行。然后SQL Server随意将其中一个作为“更新”应用。 –

+0

此外,我已经将您的示例表标记为试图让它们更易于阅读的代码 - 但我有点不确定哪些字符是示例数据的一部分,vs您可能添加了尝试格式化它们。 –

回答

2

的样本数据:

declare @RandomString table (ID int not null,ItemValue varchar(500) not null) 
insert into @RandomString(ID,ItemValue) values 
(1,'*Test"'), 
(2,'?Test*') 

declare @SearchCharReplacement table (Original varchar(500) not null,Replacement varchar(500) not null) 
insert into @SearchCharReplacement(Original,Replacement) values 
('*','`star`'), 
('?','`quest`'), 
('"','`quot`'), 
(';','`semi`') 

而且UPDATE

;With Replacements as (
    select 
     ID,ItemValue,0 as RepCount 
    from 
     @RandomString 
    union all 
    select 
     ID,SUBSTRING(REPLACE(ItemValue,Original,Replacement),1,500),rs.RepCount+1 
    from 
     Replacements rs 
      inner join 
     @SearchCharReplacement scr 
      on 
       CHARINDEX(scr.Original,rs.ItemValue) > 0 
), FinalReplacements as (
    select 
     ID,ItemValue,ROW_NUMBER() OVER (PARTITION BY ID ORDER BY RepCount desc) as rn 
    from 
     Replacements 
) 
update rs 
    set ItemValue = fr.ItemValue 
from 
    @RandomString rs 
     inner join 
    FinalReplacements fr 
     on 
      rs.ID = fr.ID and 
      rn = 1 

主要生产:

select * from @RandomString 

ID   ItemValue 
----------- ----------------------- 
1   `star`Test`quot` 
2   `quest`Test`star` 

这样做是它与不变的文本开始(顶部选择Replacements),那么它会尝试应用任何有效的替换(第二个选择i n Replacements)。它将做的是继续应用这第二个选择,根据它产生的结果,直到没有新的行产生。这被称为递归公用表表达式(CTE)。

然后,我们使用第二个CTE(这次是一个非递归函数)FinalReplacements对第一个CTE产生的所有行进行编号,为最后产生的行分配较低的行号。从逻辑上讲,这些是应用上次适用转换的结果,因此不再包含任何要替换的原始字符。因此,我们可以使用行号1对原始表执行更新。

该查询确实做了比绝对必要的更多的工作 - 对于少量的替换字符行,它不太可能太低效。我们可以通过定义单一订单来清除它,以便应用替代品。

+0

感谢您的解决方案。看起来没有其他选择。唯一的问题是我的实际问题稍微复杂一点。如果字符串包含在双引号内,我不想替'*','?'做替换。只有'''和';'在这种情况下应该被替换,为此,我相信我应该再多做一次CTE。 – Torpedo

0

跳过连接表和嵌套REPLACE函数是否工作? 或者您是否需要从其他表中获取数据?

-- perform 4 replaces in a single update statement 
UPDATE T1 
SET ItemValue = REPLACE(
        REPLACE(
        REPLACE(
         REPLACE(
         ItemValue,'*','star') 
         ItemValue,'?','quest') 
        ItemValue,'"','quot') 
        ItemValue,';','semi') 

注:我不知道,如果你需要逃避任何字符要替换