Циклы в динамическом SQL

У меня есть код, который я хотел бы применить к нескольким таблицам, но вместо того, чтобы просто копировать и заменять имена таблиц, я хотел бы использовать какой-то цикл или курсор для упрощения вещей.

Я предполагаю настроить массив имен моих таблиц и использовать индекс для итерации по списку, получения каждого имени таблицы и использования динамического SQL для перемежения имени таблицы, где это применимо в моем коде.

поскольку нет конструкции "array", насколько я знаю, в SQL, я не уверен, что это сработает.

есть идеи о том, как это сделать?

2 ответов


вот один из способов сделать это:

--Declare a table variable to hold your table names (and column names in case needed)
declare @listOfTablesToUpdate table (tableName varchar(100), columnNameToUpdate varchar(50))

--insert the tables that you want to work with.
insert into @listOfTablesToUpdate values ('Table1', 'column2')
insert into @listOfTablesToUpdate values ('Table2', 'column3')
insert into @listOfTablesToUpdate values ('Table3', 'column4')

--Cursor for iterating
declare @tableCursor cursor,
        @tableName varchar(100),
        @columnName varchar(50)

set @tableCursor = cursor for select * from @listOfTablesToUpdate

open @tableCursor
fetch next from @tableCursor into @tableName, @columnName
while(@@fetch_status = 0)
begin
    --dynamic sql
    declare @sql varchar(max)

    --Your logic here...this is just an example
    set @sql = 'update '+@tableName+' set '+@columnName+' = '+<value>+' where '+@columnName +' = '+<someothervalue>
    exec @sql

    fetch next from @tableCursor into @tableName, @columnName
end

close @tableCursor
deallocate @tableCursor

другой подход включает в себя подготовку вспомогательной функции и процедуры, которые позволяют применять различные операторы SQL к каждому объекту (таблица, база данных,и так далее) в список. Вспомогательная функция происходит от SSRS параметр вопрос и разбивает разделенный запятыми список на таблицу.

-- 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

Ниже приведен код для процедуры ProcessListSQL.

-- @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

процедура ProcessListSQL принимает два параметра. Первый строка с разделителями-запятыми, содержащая список объектов, через которые будет выполняться цикл. Второй параметр-это строка, содержащая SQL, который будет выполняться с каждым из объектов в первом параметре.

В приведенном ниже примере создаются четыре базы данных. Обратите внимание, что {rp} заменяется каждым из объектов в первом параметре, и двойные кавычки необходимы в каждом месте, где одиночные кавычки необходимы в инструкции SQL.

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%)'