动态SQL中的循环

时间:2011-12-02 00:39:31

标签: sql sql-server

我有代码,我想应用于许多表,而不是简单地复制和替换表名,我想使用某种循环或光标来简化事情。

我设想设置一个表名的数组,并使用索引迭代列表,检索每个表名,并使用动态SQL在我的代码中散布表名。

由于没有“数组”构造,据我所知,在SQL中,我不确定这是如何工作的。

关于如何解决此问题的任何想法?

2 个答案:

答案 0 :(得分:11)

这是一种方法:

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

答案 1 :(得分:0)

另一种方法涉及准备一个辅助函数和一个过程,允许人们将不同的SQL语句应用于列表中的每个对象(表,数据库,等等)。辅助函数来自SSRS Parameter question,并将逗号分隔的列表拆分为表格。

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