Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Wie kann ich alle Schlüsselfelder in einer Zeichenfolge durch Ersatzwerte aus einer Tabelle in T-SQL ersetzen?

Es gibt mehrere Möglichkeiten, dies zu tun. Ich werde zwei Möglichkeiten auflisten. Jeder hat Vor- und Nachteile. Ich persönlich würde den ersten verwenden (Dynamic SQL).

1. Dynamisches SQL

  • Vorteile:Schnell, erfordert keine Rekursion
  • Nachteile:Kann nicht zum Aktualisieren von Tabellenvariablen verwendet werden

2. Rekursiver CTE

  • Vorteile:Ermöglicht Aktualisierungen von Tabellenvariablen
  • Nachteile:Erfordert Rekursion und ist speicherintensiv, rekursive CTEs sind langsam

1.A. Dynamisches SQL:Reguläre Tabellen und Temporäre Tabellen.

Dieses Beispiel verwendet eine temporäre Tabelle als Textquelle:

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. Dynamisches SQL:Tabellenvariablen.

Erfordert, dass die Tabelle als ein bestimmter Tabellentyp definiert ist. Beispieltypdefinition:

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

Definieren Sie eine Tabellenvariable dieses Typs und verwenden Sie sie wie folgt in einer dynamischen SQL-Anweisung. Beachten Sie, dass das Aktualisieren einer Tabellenvariablen auf diese Weise nicht möglich ist.

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. Rekursiver CTE:

Der einzige Grund, warum Sie dies mit einem rekursiven CTE schreiben würden, ist, dass Sie beabsichtigen, eine Tabellenvariable zu aktualisieren, oder dass Sie Dynamic SQL irgendwie nicht verwenden dürfen (z. B. Unternehmensrichtlinie?).

Beachten Sie, dass die standardmäßige maximale Rekursionsebene 100 ist. Wenn Sie mehr als 100 Ersatzvariablen haben, sollten Sie diese Ebene erhöhen, indem Sie OPTION(MAXRECURSION 32767) hinzufügen am Ende der Abfrage (siehe Hinweise zur Abfrage ). - 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;