2013-09-16 122 views
13

是否有可能在不使用游标的情况下为选择的每一行执行一些代码?TSQL - 为选择的每一行执行代码

在我的情况: 我有一个临时表来存储complexe脚本的一些数据。最后,我想将这张表的某些信息(受某些条件限制)输出到输出中。

目前我正在使用带select的游标来限制表的行。在这个游标中,我正在使用

print '...' 

生成输出。

必须有做这种事情更简单的方法...

编辑:

create table #tmpAttributes(AttributeId uniqueidentifier, Value float, ValueString nvarchar(max), ActionId uniqueidentifier) 

insert into #tmpAttributes (AttributeId, Value, ValueString, ActionId) 
    select ID,..... -- in this select i'm doing some value conversions, if conversion is not possible i'm using -1 

insert into ActionAttribute (ActionDefinitionID, Discriminator, ID, ReferredActionID, ValueDate, ValueListID, ValueMoney, ValueString, ValueUserID) 
    select @defId, 'ActionAttributeMoneyEntity', NEWID(), ActionId, null, null, Value, null, null from #tmpAttributes 

-- afterwards there is this cursor where I'm printint all rows where Value = -1 
+2

没有足够的信息。你究竟在努力实现什么?如果你给我们一个完整的场景,你可能会发现有一个完全基于集合的方式来执行你所需要的。 – gvee

+0

为什么不在刚刚创建的“临时表”上放置一个额外的标识列,并为每一行循环播放。 –

+0

如果你只是想打印这些信息“最后”,为什么你需要一个光标呢? – DrCopyPaste

回答

19

为结果集中的每一行执行打印语句几乎需要一个游标或类似于此的方法

declare @id int, @stuff varchar(20) 
declare @tmp table 
(
    id int not null 
, stuff varchar(20) 

    primary key(id) 
) 

insert @tmp 
select id, stuff from mastertable 
where condition1 > condition2 

select top 1 @id=id, @stuff=stuff from @tmp 

while (@@rowcount > 0) 
begin 
    print @stuff 
    delete from @tmp where [email protected] 
    select top 1 @id=id, @stuff=stuff from @tmp 
end 

您仍在循环每行,但您避免了游标。由于您使用的是表格变量而不是游标,因此您可以避免表格锁定,但这不一定是更好的方法。您可以按各种可能的方式逐行处理,例如添加“已处理列”或编号所有选定行1..n并基于rownumber迭代

您只能避免逐行处理if您可以执行基于集合的操作。在您的问题中没有足够的信息来查看这是否可以在TSQL中避免这种情况现在,编写CLR过程可能会更灵活,因为您拥有更丰富的编程模型,并且循环遍历每行CLR过程中的结果集。使从CLR PROC数据库调用的每一行每一行数据库调用在TSQL

编辑 - 我看到有人已经添加了一种可能的方式转换成打印语句为一组化运作。即

declare @msg varchar(max) 
select @msg = '' 

select msg = @msg + stuff 
from mastertable where condition1 > condition2 

print @msg 

这是可以的,事实上,当我提到进行设置操作时,我指的是最佳的。如果可能,总是首选基于集合的操作。它可能不是很明显,但是字符串连接还可以在这个例子中得到非常慢太多,如果多行参与。


我说过使用temp var可以避免表锁定。这并不完全正确,因为sql server会将临时变量写入tempdb中的表中。我真正的意思是,你避免锁定生产表,因为你保证是该表的唯一用户,您没有并发访问的竞争。

我也没有打算要做出优化此。例如,内环可以跟踪id和其中条件变得其中id> @id(你也将要在ID所定义的主键)。由于临时表在每次循环迭代过程中都没有更新,我预计它会更快。

+0

仍是一个循环,但不使用“重”光标。谢谢! –

8

我认为你需要提供更多的细节,但你可能会寻找类似:

declare @msg varchar(max)=''; 

select @msg = @msg + 'Output line: ' + ColumnA + ' -- ' + 'ColumnB' + char(13)+char(10) 
from #temp 
where ... 
; 

print @msg; 
+0

因此,对于每一行变量的值将被扩展......好主意! –

+0

确保添加'OPTION(MAXDOP 1)'以防止并行性,这会带来意想不到的结果。 – gjvdkamp