TSQL - 为select的每一行执行代码

Dom*_*fer 13 sql t-sql sql-server

是否有可能以某种方式为select的每一行执行一些代码而不使用游标?

在我的情况下:我有一个临时表来存储一个复杂脚本的数据.最后,我想在输出中提示该表的某些信息(受某些条件限制).

目前我正在使用带有select的游标来限制表的行.在这个游标我正在使用

 print '...'
Run Code Online (Sandbox Code Playgroud)

生成输出.

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

编辑:

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
Run Code Online (Sandbox Code Playgroud)

Gar*_*ker 20

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

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

EDIT - I see someone already added one possible way to convert you print statements into a set oriented operation. i.e.

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

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

print @msg
Run Code Online (Sandbox Code Playgroud)

This is OK, in fact optimal what I was referring to when I said performing a set operation. A set based operation is always preferred when possible . It may not be obvious, but string concatenation can also get very slow in this example too if many rows are involved.


I said that using a temp var avoids table locking. This is not precisely true as sql server does write temp vars to a table in tempdb. What I really meant was that you avoid locking a production table and since you are guaranteed to be the only user of this table, you don't compete for concurrent access.

I also made no attempt to make optimize this. For example, the inner loop could track the id and the where condition becomes where id>@id (you will also want a primary key defined on id). Since the temp table is not updated during each loop iteration I would expect it to be faster.


Dan*_*ndi 8

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

declare @msg varchar(max)='';

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

print @msg;
Run Code Online (Sandbox Code Playgroud)