Toho lze dosáhnout několika způsoby. Uvedu dva způsoby. Každý z nich má výhody a nevýhody. Osobně bych použil první (Dynamic SQL).
1. Dynamický SQL
- Výhody:Rychlý, nevyžaduje rekurzi
- Nevýhody:Nelze použít k aktualizaci proměnných tabulky
2. Rekurzivní CTE
- Výhody:Umožňuje aktualizace proměnných tabulky
- Nevýhody:Vyžaduje rekurzi a je náročný na paměť, rekurzivní CTE jsou pomalé
1.A. Dynamické SQL:běžné tabulky a dočasné tabulky.
Tento příklad používá jako zdroj textu dočasnou tabulku:
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('[email protected]_call+','''+REPLACE(variable,'''','''''')+''','''+REPLACE(template_value,'''','''''')+''')'
FROM
#tt_repl;
DECLARE @stmt NVARCHAR(MAX)='SELECT '[email protected]_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='[email protected]_call;
EXEC sp_executesql @stmt;
SELECT * FROM #tt_text;*/
DROP TABLE #tt_repl;
DROP TABLE #tt_text;
1.B. Dynamický SQL:Proměnné tabulky.
Vyžaduje mít tabulku definovanou jako konkrétní typ tabulky. Příklad definice typu:
CREATE TYPE dbo.TEXT_TABLE AS TABLE(
id INT IDENTITY(1,1) PRIMARY KEY,
templatebody VARCHAR(MAX)
);
GO
Definujte proměnnou tabulky tohoto typu a použijte ji v příkazu Dynamic SQL následovně. Upozorňujeme, že aktualizace proměnné tabulky tímto způsobem není možná.
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('[email protected]_call+','''+REPLACE(variable,'''','''''')+''','''+REPLACE(template_value,'''','''''')+''')'
FROM
@tt_repl;
DECLARE @stmt NVARCHAR(MAX)='SELECT '[email protected]_call+' FROM @tt_text';
EXEC sp_executesql @stmt,N'@tt_text TEXT_TABLE READONLY',@tt_text;
2. Rekurzivní CTE:
Jediný důvod, proč byste to napsali pomocí rekurzivního CTE, je ten, že máte v úmyslu aktualizovat proměnnou tabulky nebo nemáte povoleno nějak používat dynamické SQL (např. firemní politika?).
Všimněte si, že výchozí maximální úroveň rekurze je 100. Pokud máte více než 100 náhradních proměnných, měli byste tuto úroveň zvýšit přidáním OPTION(MAXRECURSION 32767)
na konci dotazu (viz Nápovědy k dotazu
- 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;