Има няколко начина, по които това може да стане. Ще изброя два начина. Всеки от тях има предимства и недостатъци. Аз лично бих използвал първия (Dynamic 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('[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.Б. Динамичен 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('[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. Рекурсивен CTE:
Единствените причини, поради които бихте написали това, като използвате рекурсивен CTE, са, че възнамерявате да актуализирате променлива на таблица или не ви е разрешено да използвате Dynamic SQL по някакъв начин (напр. фирмена политика?).
Имайте предвид, че максималното ниво на рекурсия по подразбиране е 100. Ако имате повече от 100 заместващи променливи, трябва да увеличите това ниво, като добавите OPTION(MAXRECURSION 32767)
в края на заявката (вижте Съвети за заявка
- 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;