Циклы в динамическом 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%)'