TSQL:在一个查询中多次替换同一字段

TSQL:在一个查询中多次替换同一字段,tsql,replace,Tsql,Replace,给定一个替换表,是否可以将所有替换应用于同一查询中表中的一列 免责声明:我可以使用游标或动态sql来创建替换的嵌套字符串;我想知道是否可以简明扼要地完成 我有一张替换表 create table #replacements(old varchar(max), new varchar(max)) insert into #replacements values ('X','Y'), ('A','B'), ('W','V'), ('C','D') 以及要替换的值表: create table #v

给定一个替换表,是否可以将所有替换应用于同一查询中表中的一列

免责声明:我可以使用游标或动态sql来创建替换的嵌套字符串;我想知道是否可以简明扼要地完成

我有一张替换表

create table #replacements(old varchar(max), new varchar(max))
insert into #replacements values
('X','Y'),
('A','B'),
('W','V'),
('C','D')
以及要替换的值表:

create table #value(value varchar(max))
insert into #value values
('XA'),
('WC')
我想在一个查询中执行这些操作,该查询返回:

VD

有没有办法做到这一点?我试过了

update v
set value = replace(value,old,new)
from #value v,
#replacements
但这会给出(仅完成完全联接中的第一行):


WC

我给出这个答案是基于这样一个假设,即该示例只是为了方便我们而使用临时表

但是,您可以使用标量函数来实现这一点

注-如上所述。这假设函数中的表不需要是临时表

功能:

CREATE FUNCTION dbo.ReplaceCharacters (@value VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
    SELECT @value = REPLACE(@value, r.old, r.new)
    FROM replacements r --Assumes this is no longer a temp table

    RETURN @value
END
SELECT
    v.value CurrentValue,
    dbo.ReplaceCharacters(v.value) ReplacedValue
FROM #value v
+--------------+----------------+
| CurrentValue | ReplacedValue |
+--------------+----------------+
|     XA       |     YB         |
|     WC       |     VD         |
+--------------+----------------+
UPDATE #value
SET value = dbo.ReplaceCharacters(value)
这样,您就可以直接从
#值
调用该函数

查看结果集:

CREATE FUNCTION dbo.ReplaceCharacters (@value VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
    SELECT @value = REPLACE(@value, r.old, r.new)
    FROM replacements r --Assumes this is no longer a temp table

    RETURN @value
END
SELECT
    v.value CurrentValue,
    dbo.ReplaceCharacters(v.value) ReplacedValue
FROM #value v
+--------------+----------------+
| CurrentValue | ReplacedValue |
+--------------+----------------+
|     XA       |     YB         |
|     WC       |     VD         |
+--------------+----------------+
UPDATE #value
SET value = dbo.ReplaceCharacters(value)
输出:

CREATE FUNCTION dbo.ReplaceCharacters (@value VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
    SELECT @value = REPLACE(@value, r.old, r.new)
    FROM replacements r --Assumes this is no longer a temp table

    RETURN @value
END
SELECT
    v.value CurrentValue,
    dbo.ReplaceCharacters(v.value) ReplacedValue
FROM #value v
+--------------+----------------+
| CurrentValue | ReplacedValue |
+--------------+----------------+
|     XA       |     YB         |
|     WC       |     VD         |
+--------------+----------------+
UPDATE #value
SET value = dbo.ReplaceCharacters(value)
应用更改:

CREATE FUNCTION dbo.ReplaceCharacters (@value VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
    SELECT @value = REPLACE(@value, r.old, r.new)
    FROM replacements r --Assumes this is no longer a temp table

    RETURN @value
END
SELECT
    v.value CurrentValue,
    dbo.ReplaceCharacters(v.value) ReplacedValue
FROM #value v
+--------------+----------------+
| CurrentValue | ReplacedValue |
+--------------+----------------+
|     XA       |     YB         |
|     WC       |     VD         |
+--------------+----------------+
UPDATE #value
SET value = dbo.ReplaceCharacters(value)

数据样本的临时表

IF OBJECT_ID('Tempdb..#replacements') IS NOT NULL 
    DROP TABLE #replacements
IF OBJECT_ID('Tempdb..#value') IS NOT NULL 
    DROP TABLE #value;

CREATE TABLE #replacements
    (
      old VARCHAR(MAX) ,
      new VARCHAR(MAX)
    )
INSERT  INTO #replacements
VALUES  ( 'X', 'Y' ),
        ( 'A', 'B' ),
        ( 'W', 'V' ),
        ( 'C', 'D' )
CREATE TABLE #value ( value VARCHAR(MAX) )
INSERT  INTO #value
VALUES  ( 'XA' ),
        ( 'WC' )
更新前的数据

IF OBJECT_ID('Tempdb..#replacements') IS NOT NULL 
    DROP TABLE #replacements
IF OBJECT_ID('Tempdb..#value') IS NOT NULL 
    DROP TABLE #value;

CREATE TABLE #replacements
    (
      old VARCHAR(MAX) ,
      new VARCHAR(MAX)
    )
INSERT  INTO #replacements
VALUES  ( 'X', 'Y' ),
        ( 'A', 'B' ),
        ( 'W', 'V' ),
        ( 'C', 'D' )
CREATE TABLE #value ( value VARCHAR(MAX) )
INSERT  INTO #value
VALUES  ( 'XA' ),
        ( 'WC' )


使用动态查询的解决方案

DECLARE @Query AS VARCHAR(MAX)
SET @Query = 'UPDATE #value SET Value = '
    + ( SELECT  REPLICATE('REPLACE(', ( SELECT  COUNT(*) - 1
                                        FROM    #replacements
                                      )) + 'REPLACE(value'
                + ( SELECT  ',''' + r.old + ''' ,''' + r.new + ''') '
                    FROM    #replacements AS r
                  FOR
                    XML PATH('')
                  ) AS R
      )

EXEC  (@Query)
更新后的数据

IF OBJECT_ID('Tempdb..#replacements') IS NOT NULL 
    DROP TABLE #replacements
IF OBJECT_ID('Tempdb..#value') IS NOT NULL 
    DROP TABLE #value;

CREATE TABLE #replacements
    (
      old VARCHAR(MAX) ,
      new VARCHAR(MAX)
    )
INSERT  INTO #replacements
VALUES  ( 'X', 'Y' ),
        ( 'A', 'B' ),
        ( 'W', 'V' ),
        ( 'C', 'D' )
CREATE TABLE #value ( value VARCHAR(MAX) )
INSERT  INTO #value
VALUES  ( 'XA' ),
        ( 'WC' )

JBond的答案很简单,但对于任何大量行来说都很慢,因为它将是RBAR。他的函数必须逐个获取每个值,然后在替换表中运行它。对于大量的行,您将看到一些严重的性能问题

这里有一个动态查询,在我看来,它比Vasily的查询要简单一些,尽管两者实际上做的是相同的事情。对于任意数量的行,代码都应该表现得非常好。试一试:

DECLARE @Replace VARCHAR(MAX);

SELECT @Replace = COALESCE('REPLACE(' + @Replace,'REPLACE(value') + ',''' + old + ''',''' + new + ''')'
FROM #replacements


EXEC
(
    'UPDATE #value
    SET Value = ' + @Replace
)
递归解
与动态SQL解决方案相比,这不是很好。与功能相比,它更好。递归所做的是将每个更改逐个应用于整个数据集。因此,替换中的行将应用于所有数据。然后将第二个更改(行)应用于整个数据集等。。。因此,对于少量的更改,因为它通过RBAR,然后是一个不太大的值集,它可以正常工作

我喜欢这个答案!一位同事建议使用函数,但我忘了将其添加到顶部的免责声明中。然而,这实际上是为了看看是否可以在没有任何外部帮助(如函数或临时变量)的情况下在一次性查询中完成。我没有想到使用replicate生成动态sql,但我想知道这是否可以在不使用动态sql或游标的情况下完成。我必须承认,与我以前的方法相比,联合是一种更好的获取嵌套替换动态sql的方法,或者从前面答案中的复制中获取嵌套替换动态sql的方法。不过,我还是希望在没有动态sql的情况下有办法做到这一点。好吧,我也会添加一个递归解决方案,但它不会很好。很好!我不知道你能做到。它符合我的要求,所以这就是答案。如果不考虑问题的局限性,您是对的,您的第一个实际解决方案将是最干净的代码。很高兴为您提供帮助!我知道有时候动态SQL是最好的解决方案,尽管它不是最优的,因为动态SQL有很多缺点,主要是它的复杂性。我想指出的是,无论您使用什么解决方案,您都需要使用与某些新值相同的替换值对其进行联合测试。因此,如果旧值是A、B、C、D,那么测试A=D的新值。在确定解决方案正确并应用于生产表中的一大组数据之前,您需要确切地知道它将如何处理这种情况。虽然您现在可能没有这些类型的vlaues,但如果重复使用此代码,您迟早会这样做。