2011-12-02 150 views
6

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

我设想设置我的表名称的数组,并使用索引来遍历列表,检索每个表名称并使用动态SQL来散布表格名称(如果适用的话在我的代码中)。

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

有关如何解决这个问题的任何想法?

回答

7

这里是做这件事的一种方法:

--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 '[email protected]+' set '[email protected]+' = '+<value>+' where '[email protected] +' = '+<someothervalue> 
    exec @sql 

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

close @tableCursor 
deallocate @tableCursor 
+1

+1表变量是工作就像一个魅力阵列 – brian

+0

一个伟大的替代,谢谢! – Chris

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