给定一个替换表,是否可以将所有替换应用于同一查询中的表中的列?
免责声明:我可以使用游标或动态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')
我想在一个回复中执行这些操作:
YB
VD
有没有办法做到这一点?我试过了,
update v
set value = replace(value,old,new)
from #value v,
#replacements
但是这给出了(只完成了连接中的第一行):
YA
WC
答案 0 :(得分:2)
我基于假设示例仅为了方便使用临时表而给出了这个答案。
但是,您可以使用标量函数为您执行此操作。
注意 - 如上所述。这假设函数中的表不需要是临时表。
<强>功能:强>
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
这样您就可以直接从#value
。
查看结果集:
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)
答案 1 :(得分:2)
JBond的答案很简单,但对于任何大量的行来说它都是SLOW,因为它将是RBAR。他的功能必须逐个获取每个值,然后通过替换表运行它。如果有大量行,您会看到一些严重的性能问题。
这是一个动态查询,在我看来,比瓦西里有点简单,尽管两者都做同样的事情。代码应该对任意数量的行都能很好地执行。试试吧:
DECLARE @Replace VARCHAR(MAX);
SELECT @Replace = COALESCE('REPLACE(' + @Replace,'REPLACE(value') + ',''' + old + ''',''' + new + ''')'
FROM #replacements
EXEC
(
'UPDATE #value
SET Value = ' + @Replace
)
WITH CTE_replacements
AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) row_num,
old,
new
FROM #replacements
),
CTE_recursion
AS
(
SELECT REPLACE(value,old,new) AS value,
1 AS cnt
FROM #value
CROSS APPLY (SELECT old,new FROM CTE_replacements WHERE row_num = 1) CA
UNION ALL
SELECT REPLACE(value,old,new) AS value,
cnt + 1
FROM cte_recursion A
CROSS APPLY (SELECT old,new FROM CTE_replacements WHERE row_num = cnt + 1) CA
)
SELECT TOP(SELECT COUNT(*) FROM #value) *
FROM CTE_recursion
ORDER BY 2 DESC
OPTION (MAXRECURSION 0)
与动态SQL解决方案相比,这并不是很好。与功能相比,它更好。递归的作用是将每个更改逐个应用于整个数据集。因此,替换行将应用于所有数据。然后第二个更改(行)应用于整个数据集等...因此,对于小数量的更改,因为它通过它RBAR,然后一个不太大的值集,它将工作正好。
答案 2 :(得分:1)
数据样本的临时表
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)
更新后的数据