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

发布于 2024-10-24 11:59:50 字数 547 浏览 1 评论 0原文

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一身骄傲 2024-10-31 11:59:50

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

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

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

You cannot normally avoid looping since you are calling EXEC, which cannot be done as a SET-based operation; it has to be done one by one.

If you just want to avoid CURSOR in general, you can implement it using a WHILE loop.

Otherwise, another option is to use a SELECT + FOR XML statement which builds the EXEC statements as a single NVARCHAR(MAX) statement into a variable, then EXEC just that dynamic SQL.

吃兔兔 2024-10-31 11:59:50

好的,这个示例只执行条件 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 是我的表,其中包含要处理的行(在您的示例中为“帐户”)。 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 表使用不同的名称。 合并语句正在被轻微滥用,因为您不能使用OUTPUT 子句,从插入语句引用其他表。但我们使用它是为了捕获从 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 的所有工作,始终保持代码集为基础。

Okay, this example only does the insert for condition X, but hopefully shows you the way you could proceed:

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 is my table containing rows to be dealt with (in your example, Accounts). T1 and T2 are two tables that are currently inserted into/updated by your p_x procedure.

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

Just some sample data - I've got 3 rows, 2 of which match "condition 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

For your actual work, you'd want 3 copies of the above - one for each of x, y and z. If it's inside the same stored proc, you'd need to use a different name for the @Inter table. The merge statement is being slightly abused, because you can't use an OUTPUT clause that references other tables from an insert statement. But we're using that in order to capture the generated IDENTITY values from T1, along with the corresponding data that's going to be inserted into other tables.

So now we'll use the table variable @Inter for a further insert into T2, and to eventually update Val to indicate that the rows have been processed. If there's a chain of tables where you need to insert and grab identity values, you'd need to introduce more merge statements and table variables.

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

And we get our results:

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)

So we've performed all of our work for condition X, keeping the code set based throughout.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文