T-SQL 循环查询结果

Posted

技术标签:

【中文标题】T-SQL 循环查询结果【英文标题】:T-SQL loop over query results 【发布时间】:2012-08-07 19:29:50 【问题描述】:

我运行了一个查询 select @id=table.id from table,我需要遍历结果,以便为每一行执行一个存储过程 exec stored_proc @varName=@id,@otherVarName='test'

如何在 T-SQL 脚本中执行此操作?

【问题讨论】:

好吧,我什么都没试过。我不知道该怎么做。我想我可以尝试编写一个C 样式循环,但我怀疑这会奏效。也许是一个php 风格的循环,但我再次怀疑这也行得通。我需要在 T-SQL 中完成这一切,因为我可以在 SMS 中运行 SQL,而无需外部语言进行循环......首先是这个问题。 @Shedal 这些 cmets/answers(尽管比“google it”答案少)具有讽刺意味的是,随着时间的推移,它们往往会成为谷歌搜索结果中的佼佼者。因此,反过来,当有人寻找某个问题的解决方案时,他首先会遇到的是对遇到问题但自己没有费心寻找答案的其他人的抨击(通常是有道理的)。从长远来看,这会让那些真正试图寻找答案的人感到厌烦。 @MarcinHabuszewski 好吧,老实说,如果一个常见问题没有正确答案,它就不会出现在 Google 搜索结果的第一页上。正常。 【参考方案1】:

在这种情况下,您可以使用 CURSOR:

DECLARE @id INT
DECLARE @name NVARCHAR(100)
DECLARE @getid CURSOR

SET @getid = CURSOR FOR
SELECT table.id,
       table.name
FROM   table

OPEN @getid
FETCH NEXT
FROM @getid INTO @id, @name
WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC stored_proc @varName=@id, @otherVarName='test', @varForName=@name
    FETCH NEXT
    FROM @getid INTO @id, @name
END

CLOSE @getid
DEALLOCATE @getid

修改为显示表格中的多个参数。

【讨论】:

如果你想从表中获取超过 id 怎么办? @HenleyChiu 我已经修改了答案以包含一个我相信会起作用的新参数@name,但是我现在已经有一段时间没有使用光标了!。 @XN16 使用超过 id 不起作用,必须找到解决方法:-(【参考方案2】:

你可以这样做:

create procedure test
as
BEGIN

    create table #ids
    (
        rn int,
        id int
    )

    insert into #ids (rn, id)
    select distinct row_number() over(order by id) as rn, id
    from table

    declare @id int
    declare @totalrows int = (select count(*) from #ids)
    declare @currentrow int = 0

    while @currentrow <  @totalrows  
    begin 
        set @id = (select id from #ids where rn = @currentrow)

        exec stored_proc @varName=@id, @otherVarName='test'

        set @currentrow = @currentrow +1
    end  

END

【讨论】:

我更喜欢这种方法,因为光标比while循环慢 与 set 操作(即制作一个大的选择/更新语句)相比,游标更慢。与创建临时表和做一些 writes 相比,我不太确定。请参阅techrepublic.com/blog/the-enterprise-cloud/… 我做了自己的测试,我同意。当您遇到锁定问题时,临时表可能会更快,并且您可以更快地获取子集然后对其进行处理。这取决于我猜... 在 SQL Server 上,这在循环的第一次迭代中给了我一个错误,因为 row_number() 从 1 开始,但 @currentrow 被初始化为 0【参考方案3】:

我更喜欢的解决方案是 Microsoft KB 111401 http://support.microsoft.com/kb/111401。

链接指的是3个例子:

本文介绍了可用于在存储过程、触发器或 Transact-SQL 批处理中模拟类似游标的 FETCH-NEXT 逻辑的各种方法。

/*********** example 1 ***********/ 

declare @au_id char( 11 )

set rowcount 0
select * into #mytemp from authors

set rowcount 1

select @au_id = au_id from #mytemp

while @@rowcount <> 0
begin
    set rowcount 0
    select * from #mytemp where au_id = @au_id
    delete #mytemp where au_id = @au_id

    set rowcount 1
    select @au_id = au_id from #mytemp
end
set rowcount 0



/********** example 2 **********/ 

declare @au_id char( 11 )

select @au_id = min( au_id ) from authors

while @au_id is not null
begin
    select * from authors where au_id = @au_id
    select @au_id = min( au_id ) from authors where au_id > @au_id
end



/********** example 3 **********/ 

set rowcount 0
select NULL mykey, * into #mytemp from authors

set rowcount 1
update #mytemp set mykey = 1

while @@rowcount > 0
begin
    set rowcount 0
    select * from #mytemp where mykey = 1
    delete #mytemp where mykey = 1
    set rowcount 1
    update #mytemp set mykey = 1
end
set rowcount 0

【讨论】:

【参考方案4】:
DECLARE @id INT
DECLARE @name NVARCHAR(100)
DECLARE @getid CURSOR

SET @getid = CURSOR FOR
SELECT table.id,
       table.name
FROM   table

WHILE 1=1
BEGIN

    FETCH NEXT
    FROM @getid INTO @id, @name
    IF @@FETCH_STATUS < 0 BREAK

    EXEC stored_proc @varName=@id, @otherVarName='test', @varForName=@name

END

CLOSE @getid
DEALLOCATE @getid

【讨论】:

只需在“WHILE 1=1”之前添加“OPEN @getid”【参考方案5】:
DECLARE @id INT
DECLARE @filename NVARCHAR(100)
DECLARE @getid CURSOR

SET @getid = CURSOR FOR
SELECT top 3 id,
filename 
FROM  table

OPEN @getid
WHILE 1=1
BEGIN

    FETCH NEXT
    FROM @getid INTO @id, @filename
    IF @@FETCH_STATUS < 0 BREAK

    print @id

END


CLOSE @getid
DEALLOCATE @getid

【讨论】:

【参考方案6】:

试试这个:

declare @i tinyint = 0,
    @count tinyint,
    @id int,
    @name varchar(max)

select @count = count(*) from table
while (@i < @count)
begin
    select @id = id, @name = name from table
    order by nr asc offset @i rows fetch next 1 rows only

    exec stored_proc @varName = @id, @otherVarName = 'test', @varForName = @name

    set @i = @i + 1
end

【讨论】:

以上是关于T-SQL 循环查询结果的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL:手动锁定表几分钟[重复]

使用 T-SQL 查询 XML 节点得到错误的结果集

存在查询未产生预期结果时的 T-SQL 案例

T-SQL,在视图中重复相同的标量子查询性能

T-SQL 嵌套子查询

T-SQL查询2