How can I replace all key fields in a string with replacement values from a table in T-SQL?

后端 未结 3 1064
情话喂你
情话喂你 2021-01-14 06:40

I have a table like:

 TemplateBody
 ---------------------------------------------------------------------
 1.This is To inform #FirstName# about the issues r         


        
3条回答
  •  走了就别回头了
    2021-01-14 07:09

    There are several ways this can be done. I'll list two ways. Each one has advantages and disadvantages. I would personally use the first one (Dynamic SQL).

    1. Dynamic SQL

    • Advantages: Fast, doesn't require recursion
    • Disadvantages: Can't be used to update table variables

    2. Recursive CTE

    • Advantages: Allows updates of table variables
    • Disadvantages: Requires recursion and is memory intensive, recursive CTE's are slow

    1.A. Dynamic SQL: Regular tables and Temporary tables.

    This example uses a temporary table as the text source:

    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. Dynamic SQL: Table variables.

    Requires to have the table defined as a specific table type. Example type definition:

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

    Define a table variable of this type, and use it in a Dynamic SQL statement as follows. Note that updating a table variable this way is not possible.

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

    The only reasons why you would write this using a recursive CTE is that you intend to update a table variable, or you are not allowed to use Dynamic SQL somehow (eg company policy?).

    Note that the default maximum recursion level is 100. If you have more than a 100 replacement variables you should increase this level by adding OPTION(MAXRECURSION 32767) at the end of the query (see 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;
    

提交回复
热议问题