如何避免使用Cursor实现此伪代码 - SQL Server

时间:2011-03-18 06:20:15

标签: sql-server tsql sql-server-2008 cursor

CREATE PROCEDURE p_processDataFor @accountId
BEGIN

    for each item in 
      (select * from Accounts where accountId   = @accountId and isProcessed = 0)
    BEGIN
        CASE current row
            WHEN  has x Condition THEN
                exec p_x <Pass all data of current row>
            WHEN  has y Condition THEN
                exec p_y <Pass all data of current row>
            WHEN  has z Condition THEN
                exec p_z <Pass all data of current row>
            END
    END

END

2 个答案:

答案 0 :(得分:2)

由于您正在调用EXEC,因此通常无法避免循环,这不能作为基于SET的操作完成;它必须一个接一个地完成。

如果您只想避免使用CURSOR,可以使用WHILE循环来实现它。

否则,另一个选择是使用SELECT + FOR XML语句将EXEC语句作为单个NVARCHAR(MAX)语句构建到变量中,然后EXEC就是那个动态SQL。

答案 1 :(得分:1)

好的,这个例子只对条件X进行插入,但希望能告诉你如何继续:

create table T1 (
    ID int IDENTITY(1,1) not null,
    Val1 varchar(10) not null,
    constraint PK_T1 PRIMARY KEY (ID)
)
go
create table T2 (
    ID int not null,
    Val2 varchar(10) not null,
    constraint PK_T2 PRIMARY KEY (ID)
)
go
create table Val (
    ID int IDENTITY(1,1) not null,
    Val1 varchar(10) not null,
    Val2 varchar(10) not null,
    Processed bit not null,
    CondX bit not null
)
go

Val是我的表,包含要处理的行(在您的示例中为Accounts)。 T1和T2是目前由p_x程序插入/更新的两个表。

insert into Val(Val1,Val2,Processed,CondX)
select 'abc','def',0,1 union all
select 'ghi','jkl',0,0 union all
select 'mno','pqr',0,1
go

只是一些示例数据 - 我有3行,其中2行匹配“条件x”:

declare @Inter table (ValID int,T1ID int,Val2 varchar(10))

;merge into T1 using (select * from Val where CondX=1) Val on 1=0
when not matched then insert (Val1) values (Val.Val1)
output inserted.ID,Val.ID,Val.Val2 into @Inter (T1ID,ValID,Val2);

insert into T2(ID,Val2)
select T1ID,Val2 from @Inter

update Val set Processed = 1 where ID in (select ValID from @Inter)
go

对于您的实际工作,您需要上述3份 - x,y和z各一份。如果它在同一个存储过程中,则需要为@Inter表使用不同的名称。 merge statement稍有滥用,因为您不能使用引用insert语句中其他表的OUTPUT clause。但是我们正在使用它来捕获T1中生成的IDENTITY值,以及将要插入到其他表中的相应数据。

所以现在我们将使用表变量@Inter进一步插入T2,并最终更新Val以指示行已被处理。如果需要插入并获取标识值的表链,则需要引入更多的合并语句和表变量。

select * from Val
select * from T1
select * from T2

我们得到了结果:

ID          Val1       Val2       Processed CondX
----------- ---------- ---------- --------- -----
1           abc        def        1         1
2           ghi        jkl        0         0
3           mno        pqr        1         1

(3 row(s) affected)

ID          Val1
----------- ----------
1           abc
2           mno

(2 row(s) affected)

ID          Val2
----------- ----------
1           def
2           pqr

(2 row(s) affected)

因此,我们已经完成了条件X的所有工作,始终保持代码集。