sql >> Databasteknik >  >> RDS >> Sqlserver

Hur kan jag ersätta alla nyckelfält i en sträng med ersättningsvärden från en tabell i T-SQL?

Det finns flera sätt detta kan göras. Jag ska lista två sätt. Var och en har fördelar och nackdelar. Jag skulle personligen använda den första (Dynamic SQL).

1. Dynamisk SQL

  • Fördelar:Snabb, kräver ingen rekursion
  • Nackdelar:Kan inte användas för att uppdatera tabellvariabler

2. Rekursiv CTE

  • Fördelar:Tillåter uppdateringar av tabellvariabler
  • Nackdelar:Kräver rekursion och är minneskrävande, rekursiva CTE är långsamma

1.A. Dynamisk SQL:Vanliga tabeller och tillfälliga tabeller.

Det här exemplet använder en temporär tabell som textkälla:

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. Dynamisk SQL:Tabellvariabler.

Kräver att tabellen har definierats som en specifik tabelltyp. Exempel på typdefinition:

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

Definiera en tabellvariabel av denna typ och använd den i en dynamisk SQL-sats enligt följande. Observera att det inte är möjligt att uppdatera en tabellvariabel på detta sätt.

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

De enda anledningarna till att du skulle skriva detta med en rekursiv CTE är att du har för avsikt att uppdatera en tabellvariabel, eller så får du inte använda Dynamic SQL på något sätt (t.ex. företagspolicy?).

Observera att den maximala standardrekursionsnivån är 100. Om du har fler än 100 ersättningsvariabler bör du öka denna nivå genom att lägga till OPTION(MAXRECURSION 32767) i slutet av frågan (se Frågetips - 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;


  1. Fråga som returnerar exakt antal rader

  2. Uppdatera en av 2 dubbletter i en sql-serverdatabastabell

  3. MySQL #1243 Okänd förberedd satshanterare (stmt) ges till EXECUTE

  4. Hur skriver jag ut alla fält för alla tabeller i mysql-databasen?