13

是否可以在不使用游标的情况下以某种方式为选择的每一行执行一些代码?

就我而言:我有一个临时表来存储复杂脚本的一些数据。最后,我想将此表的一些信息(受某些条件限制)输出到输出。

目前我正在使用带有选择的游标来限制表的行。在这个光标中我正在使用

 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
4

2 回答 2

20

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

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 id=@id
  select top 1 @id=id, @stuff=stuff from @tmp
end

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

如果您可以执行基于集合的操作,则只能避免逐行处理。您的问题中没有足够的信息来查看这在 TSQL 中是否可以避免

现在,编写 CLR proc 可能更加灵活,因为您拥有更丰富的编程模型,并且在 CLR proc 中循环遍历结果集的每一行的开销很小。从 CLR proc 为数据库从 TSQL 中的每一行调用的每一行进行数据库调用

编辑 - 我看到有人已经添加了一种可能的方法来将您的打印语句转换为面向集合的操作。IE

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

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

print @msg

这没关系,实际上是我所说的执行集合操作时所指的最优。如果可能,总是首选基于集合的操作。这可能并不明显,但如果涉及到许多行,则在此示例中字符串连接也会变得非常慢。


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

我也没有尝试对此进行优化。例如,内部循环可以跟踪 id 并且 where 条件变为 where id>@id(您还需要在 id 上定义主键)。由于临时表在每次循环迭代期间都不会更新,我希望它会更快。

于 2013-09-16T12:30:15.143 回答
9

我认为您需要提供更多详细信息,但您可能正在寻找类似的内容:

declare @msg varchar(max)='';

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

print @msg;
于 2013-09-16T12:27:24.403 回答