如何使用T-SQL中的表替换字符串中的所有键字段

时间:2016-02-01 12:22:00

标签: sql-server tsql replace

我有一张表:

 TemplateBody
 ---------------------------------------------------------------------
 1.This is To inform #FirstName# about the issues regarding #Location#

此处的密钥字符串是#FirstName##Location#,它们通过哈希标记进行区分。

我有另一个包含替换值的表:

Variables     | TemplateValues
-----------------------------
1.#FirstName# | Joseph William
2.#Location#  | Alaska

我需要用第一个表中的值替换这两个键字符串。

3 个答案:

答案 0 :(得分:2)

有几种方法可以做到这一点。我将列出两种方式。每个人都有优点和缺点。我个人会使用第一个(动态SQL)。

<强> 1。动态SQL

  • 优点:快速,不需要递归
  • 缺点:不能用于更新表变量

<强> 2。递归CTE

  • 优点:允许更新表变量
  • 缺点:需要递归并且内存密集,递归CTE很慢

<强> 1.A。动态SQL:常规表和临时表。

此示例使用临时表作为文本源:

CREATE TABLE #tt_text(templatebody VARCHAR(MAX));
INSERT INTO #tt_text(templatebody)VALUES
    ('This is to inform #first_name# about the issues regarding #location#');

CREATE TABLE #tt_repl(variable VARCHAR(256),template_value VARCHAR(8000));
INSERT INTO #tt_repl(variable,template_value)VALUES
    ('#first_name#','Joseph William'),
    ('#location#','Alaska');

DECLARE @rep_call NVARCHAR(MAX)='templatebody';
SELECT
    @rep_call='REPLACE('+@rep_call+','''+REPLACE(variable,'''','''''')+''','''+REPLACE(template_value,'''','''''')+''')'
FROM
    #tt_repl;

DECLARE @stmt NVARCHAR(MAX)='SELECT '+@rep_call+' FROM #tt_text';
EXEC sp_executesql @stmt;

/* Use these statements if you want to UPDATE the source rather than SELECT from it
DECLARE @stmt NVARCHAR(MAX)='UPDATE #tt_text SET templatebody='+@rep_call;
EXEC sp_executesql @stmt;
SELECT * FROM #tt_text;*/

DROP TABLE #tt_repl;
DROP TABLE #tt_text;

<强> 1.B。动态SQL:表变量。

要求将表定义为特定的表类型。示例类型定义:

CREATE TYPE dbo.TEXT_TABLE AS TABLE(
    id INT IDENTITY(1,1) PRIMARY KEY,
    templatebody VARCHAR(MAX)
);
GO

定义此类型的表变量,并在动态SQL语句中使用它,如下所示。请注意,无法以这种方式更新表变量。

DECLARE @tt_text dbo.TEXT_TABLE;
INSERT INTO @tt_text(templatebody)VALUES
    ('This is to inform #first_name# about the issues regarding #location#');

DECLARE @tt_repl TABLE(id INT IDENTITY(1,1),variable VARCHAR(256),template_value VARCHAR(8000));
INSERT INTO @tt_repl(variable,template_value)VALUES
    ('#first_name#','Joseph William'),
    ('#location#','Alaska');

DECLARE @rep_call NVARCHAR(MAX)='templatebody';
SELECT
    @rep_call='REPLACE('+@rep_call+','''+REPLACE(variable,'''','''''')+''','''+REPLACE(template_value,'''','''''')+''')'
FROM
    @tt_repl;

DECLARE @stmt NVARCHAR(MAX)='SELECT '+@rep_call+' FROM @tt_text';
EXEC sp_executesql @stmt,N'@tt_text TEXT_TABLE READONLY',@tt_text;

<强> 2。递归CTE:

使用递归CTE编写此函数的唯一原因是您打算更新表变量,或者您不允许以某种方式使用动态SQL(例如公司策略?)。

请注意,默认的最大递归级别为100.如果您有超过100个替换变量,则应通过在查询末尾添加OPTION(MAXRECURSION 32767)来提高此级别(请参阅Query Hints - {{ 1}})。

MAXRECURSION

答案 1 :(得分:0)

只要变量的值是唯一的('#FirstName#'等),您就可以将每个变量加入到包含TemplateBody的表中:

select replace(replace(t.TemplateBody,'#FirstName#',variable.theVariable),'#Location#',variable2.theVariable)
from
[TemplateBodyTable] t
left join
(
select TemplateValues theVariable,Variables
from [VariablesTable] v
) variable on variable.Variables='#FirstName#'
left join
(
select TemplateValues theVariable,Variables
from [VariablesTable] v
) variable2 on variable2.Variables='#Location#'

答案 2 :(得分:0)

公用表表达式允许您遍历模板并使用变量表替换该模板中的所有变量。如果您有很多变量,则递归级别可能会超出默认的100次递归限制。您可以根据需要使用MAXRECURSION选项。

DECLARE @Templates TABLE(Body nvarchar(max));
INSERT INTO @Templates VALUES ('This is to inform #FirstName# about the issues regarding #Location#');

DECLARE @Variables TABLE(Name nvarchar(50), Value nvarchar(max));
INSERT INTO @Variables VALUES ('#FirstName#', 'Joseph William'),
                              ('#Location#', 'Alaska');

WITH replacing(Body, Level) AS
(
    SELECT t.Body, 1 FROM @Templates t
    UNION ALL    
    SELECT REPLACE(t.Body, v.Name, v.Value), t.Level + 1 
    FROM replacing t INNER JOIN @Variables v ON PATINDEX('%' + v.Name + '%', t.Body) > 0
)
SELECT TOP 1 r.Body
FROM replacing r
WHERE r.Level = (SELECT MAX(Level) FROM replacing)
OPTION (MAXRECURSION 0);