Loops within dynamic SQL

前端 未结 2 1408
长发绾君心
长发绾君心 2021-02-15 05:26

I have code that I\'d like to apply to a number of tables but rather than simply copy and replace table names, I\'d like to use some kind of loop or cursor to simplify things.

2条回答
  •  深忆病人
    2021-02-15 06:01

    Another approach involves preparing a helper function and a procedure that allow one to apply different SQL statements to each object (table, database, et cetera) in a list. The helper function comes from a SSRS Parameter question and splits apart a comma delimited list into a table.

    -- from https://stackoverflow.com/questions/512105/passing-multiple-values-for-a-single-parameter-in-reporting-services
    CREATE FUNCTION [dbo].[fn_MVParam]
       (@RepParam NVARCHAR(4000), @Delim CHAR(1)= ',')
    RETURNS @Values TABLE (Param NVARCHAR(4000))AS
      BEGIN
      DECLARE @chrind INT
      DECLARE @Piece NVARCHAR(100)
      SELECT @chrind = 1 
      WHILE @chrind > 0
        BEGIN
          SELECT @chrind = CHARINDEX(@Delim,@RepParam)
          IF @chrind  > 0
            SELECT @Piece = LEFT(@RepParam,@chrind - 1)
          ELSE
            SELECT @Piece = @RepParam
          INSERT  @Values(Param) VALUES(CAST(@Piece AS VARCHAR))
          SELECT @RepParam = RIGHT(@RepParam,LEN(@RepParam) - @chrind)
          IF LEN(@RepParam) = 0 BREAK
        END
      RETURN
      END
    GO
    

    Below is the code for the ProcessListSQL procedure.

    -- @SQL to execute shall include {RP} as the replacement expression that
    -- will evaluate to all the items in the comma delimited list
    -- Also, please include a double quote " rather than two single quotes ''
    -- in the input statement.
    
    CREATE PROCEDURE [dbo].[ProcessListSQL]  (
        @CommaDelimitedList AS NVARCHAR(MAX),
        @SQLtoExecute AS NVARCHAR(MAX) )
    AS BEGIN
    
    DECLARE @Statements TABLE
    (   PK INT IDENTITY(1,1) PRIMARY KEY,
        SQLObject NVARCHAR (MAX)
    )
    
    SET @SQLtoExecute = REPLACE (@SQLtoExecute, '"', '''')
    
    INSERT INTO @Statements
    SELECT PARAM FROM [dbo].[fn_MVParam](@CommaDelimitedList,',')
    
    DECLARE @i INT
    SELECT @i = MIN(PK) FROM @Statements
    DECLARE @max INT
    SELECT @max = MAX(PK) FROM @Statements
    
    DECLARE @SQL AS NVARCHAR(MAX) = NULL
    DECLARE @Object AS NVARCHAR(MAX) = NULL
    
    WHILE @i <= @max 
        BEGIN       
            SELECT @Object = SQLObject FROM @Statements WHERE PK = @i       
            SET @SQL = REPLACE(@SQLtoExecute, '{RP}', @Object)
    
            -- Uncommend below to check the SQL
            -- PRINT @SQL
    
            EXECUTE sp_executesql @SQL
    
            SELECT @Object = NULL
            SELECT @SQL = NULL
            SET @i = @i + 1
        END
    END      
    GO
    

    The ProcessListSQL procedure take two parameters. The first is a comma delimited string that contains the list of objects that will be cycled through. The second parameter is a string that contains the SQL that will be executed with each of the objects in the first parameter.

    In the below example, four databases are created. Note that {rp} is replaced with each of the objects in the first parameter and double quotes are needed in each place where single quotes are needed in the SQL statement.

    EXECUTE ProcessListSQL 'rice,apples,cheese,tomatos',
    'CREATE DATABASE [{rp}] CONTAINMENT = NONE 
            ON  PRIMARY ( NAME = N"{rp}", 
            FILENAME = N"D:\data\user\{rp}.mdf" , 
            SIZE = 4096KB , 
            FILEGROWTH = 1024KB ) 
            LOG ON 
        ( NAME = N"{rp}_log", 
            FILENAME = N"D:\DATA\USER\{rp}_log.ldf" , 
            SIZE = 1024KB , 
            FILEGROWTH = 10%)'
    

提交回复
热议问题