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

結果セットの各行に対して 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

あなたはまだ各行をループしていますが、カーソルを避けています。カーソルの代わりにテーブル変数を使用しているため、テーブルのロックを回避できますが、これは必ずしもより良いアプローチではありません。「処理された列」を追加したり、選択したすべての行に番号を付けたり、行番号に基づいて反復したりするなど、さまざまな方法で行ごとに処理できます。

セットベースの操作を実行できる場合にのみ、行ごとの処理を回避できます。あなたの質問には、これがTSQLで回避可能かどうかを確認するのに十分な情報がありません

現在、CLR proc の作成はより柔軟である可能性があります。これは、より豊富なプログラミング モデルがあり、CLR proc 内の結果セットの各行をループするオーバーヘッドがほとんどないためです。データベースがTSQLの各行から呼び出す各行に対してCLR procからデータベース呼び出しを行う

編集 - print ステートメントをセット指向の操作に変換する 1 つの可能な方法を誰かが既に追加しているようです。すなわち

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

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

print @msg

これは問題ありません。実際、セット操作を実行すると言ったときに言及していたのは最適です。可能であれば、セットベースの操作が常に推奨されます。明らかではないかもしれませんが、この例でも、多くの行が関係している場合、文字列の連結が非常に遅くなる可能性があります。


一時変数を使用すると、テーブルのロックが回避されると言いました。SQL サーバーは一時変数を 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 に答える