如何用 T-SQL 中的 table 中的替换值替换字符串中的所有关键字段?
How can I replace all key fields in a string with replacement values from a table in T-SQL?
我有一个 table 像:
TemplateBody
---------------------------------------------------------------------
1.This is To inform #FirstName# about the issues regarding #Location#
这里的关键字符串是#FirstName#
和#Location#
,它们通过哈希标签来区分。
我有另一个 table 替换值:
Variables | TemplateValues
-----------------------------
1.#FirstName# | Joseph William
2.#Location# | Alaska
我需要用第一个 table 中的值替换这两个键字符串。
有几种方法可以做到这一点。我会列出两种方式。每一个都有优点和缺点。我个人会使用第一个(动态 SQL)。
1.动态 SQL
- 优点:速度快,不需要递归
- 缺点:不能用于更新table变量
2。递归 CTE
- 优点:允许更新 table 个变量
- 缺点:需要递归并且是内存密集型的,递归 CTE 很慢
1.A。动态 SQL:常规 table 和临时 table。
此示例使用临时 table 作为文本源:
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: Table 个变量。
需要将 table 定义为特定的 table 类型。示例类型定义:
CREATE TYPE dbo.TEXT_TABLE AS TABLE(
id INT IDENTITY(1,1) PRIMARY KEY,
templatebody VARCHAR(MAX)
);
GO
定义一个这种类型的 table 变量,并在 Dynamic SQL 语句中使用它,如下所示。请注意,无法以这种方式更新 table 变量。
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 编写此代码的唯一原因是您打算更新 table 变量,或者您不允许以某种方式使用动态 SQL(例如公司政策? ).
请注意,默认的最大递归级别为 100。如果您有超过 100 个替换变量,您应该通过在查询末尾添加 OPTION(MAXRECURSION 32767)
来增加此级别(请参阅 Query Hints - MAXRECURSION
).
DECLARE @tt_text TABLE(id INT IDENTITY(1,1),templatebody VARCHAR(MAX));
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');
;WITH cte AS (
SELECT
t.id,
l=1,
templatebody=REPLACE(t.templatebody,r.variable,r.template_value)
FROM
@tt_text AS t
INNER JOIN @tt_repl AS r ON r.id=1
UNION ALL
SELECT
t.id,
l=l+1,
templatebody=REPLACE(t.templatebody,r.variable,r.template_value)
FROM
cte AS t
INNER JOIN @tt_repl AS r ON r.id=t.l+1
)
UPDATE
@tt_text
SET
templatebody=cte.templatebody
FROM
@tt_text AS t
INNER JOIN cte ON
cte.id=t.id
WHERE
cte.l=(SELECT MAX(id) FROM @tt_repl);
/* -- if instead you wanted to select the replaced strings, comment out
-- the above UPDATE statement, and uncomment this SELECT statement:
SELECT
templatebody
FROM
cte
WHERE
l=(SELECT MAX(id) FROM @tt_repl);*/
SELECT*FROM @tt_text;
只要变量的值是唯一的(“#FirstName#”等),您就可以将每个变量连接到包含 TemplateBody 的 table:
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#'
一个常见的 table 表达式允许您遍历模板并使用变量 table 替换该模板中的所有变量。如果您有很多变量,递归级别可能会超过 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);
我有一个 table 像:
TemplateBody
---------------------------------------------------------------------
1.This is To inform #FirstName# about the issues regarding #Location#
这里的关键字符串是#FirstName#
和#Location#
,它们通过哈希标签来区分。
我有另一个 table 替换值:
Variables | TemplateValues
-----------------------------
1.#FirstName# | Joseph William
2.#Location# | Alaska
我需要用第一个 table 中的值替换这两个键字符串。
有几种方法可以做到这一点。我会列出两种方式。每一个都有优点和缺点。我个人会使用第一个(动态 SQL)。
1.动态 SQL
- 优点:速度快,不需要递归
- 缺点:不能用于更新table变量
2。递归 CTE
- 优点:允许更新 table 个变量
- 缺点:需要递归并且是内存密集型的,递归 CTE 很慢
1.A。动态 SQL:常规 table 和临时 table。
此示例使用临时 table 作为文本源:
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: Table 个变量。
需要将 table 定义为特定的 table 类型。示例类型定义:
CREATE TYPE dbo.TEXT_TABLE AS TABLE(
id INT IDENTITY(1,1) PRIMARY KEY,
templatebody VARCHAR(MAX)
);
GO
定义一个这种类型的 table 变量,并在 Dynamic SQL 语句中使用它,如下所示。请注意,无法以这种方式更新 table 变量。
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 编写此代码的唯一原因是您打算更新 table 变量,或者您不允许以某种方式使用动态 SQL(例如公司政策? ).
请注意,默认的最大递归级别为 100。如果您有超过 100 个替换变量,您应该通过在查询末尾添加 OPTION(MAXRECURSION 32767)
来增加此级别(请参阅 Query Hints - MAXRECURSION
).
DECLARE @tt_text TABLE(id INT IDENTITY(1,1),templatebody VARCHAR(MAX));
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');
;WITH cte AS (
SELECT
t.id,
l=1,
templatebody=REPLACE(t.templatebody,r.variable,r.template_value)
FROM
@tt_text AS t
INNER JOIN @tt_repl AS r ON r.id=1
UNION ALL
SELECT
t.id,
l=l+1,
templatebody=REPLACE(t.templatebody,r.variable,r.template_value)
FROM
cte AS t
INNER JOIN @tt_repl AS r ON r.id=t.l+1
)
UPDATE
@tt_text
SET
templatebody=cte.templatebody
FROM
@tt_text AS t
INNER JOIN cte ON
cte.id=t.id
WHERE
cte.l=(SELECT MAX(id) FROM @tt_repl);
/* -- if instead you wanted to select the replaced strings, comment out
-- the above UPDATE statement, and uncomment this SELECT statement:
SELECT
templatebody
FROM
cte
WHERE
l=(SELECT MAX(id) FROM @tt_repl);*/
SELECT*FROM @tt_text;
只要变量的值是唯一的(“#FirstName#”等),您就可以将每个变量连接到包含 TemplateBody 的 table:
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#'
一个常见的 table 表达式允许您遍历模板并使用变量 table 替换该模板中的所有变量。如果您有很多变量,递归级别可能会超过 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);