ストアドプロシージャで作成した動的SQLステートメントがあります。カーソルを使用して結果を反復処理する必要があります。正しい構文を理解するのに苦労しています。これが私がやっていることです。
SELECT @SQLStatement = 'SELECT userId FROM users'
DECLARE @UserId
DECLARE users_cursor CURSOR FOR
EXECUTE @SQLStatment --Fails here. Doesn't like this
OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC asp_DoSomethingStoredProc @UserId
END
CLOSE users_cursor
DEALLOCATE users_cursor
これを行う正しい方法は何ですか?
カーソルはselectステートメントのみを受け入れるため、SQLが本当に動的である必要がある場合は、実行中のステートメントの宣言カーソル部分を作成します。以下が機能するには、サーバーでグローバルカーソルを使用する必要があります。
Declare @UserID varchar(100)
declare @sqlstatement nvarchar(4000)
--move declare cursor into sql to be executed
set @sqlstatement = 'Declare users_cursor CURSOR FOR SELECT userId FROM users'
exec sp_executesql @sqlstatement
OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId
WHILE @@FETCH_STATUS = 0
BEGIN
Print @UserID
EXEC asp_DoSomethingStoredProc @UserId
FETCH NEXT FROM users_cursor --have to fetch again within loop
INTO @UserId
END
CLOSE users_cursor
DEALLOCATE users_cursor
グローバルカーソルの使用を回避する必要がある場合は、動的SQLの結果を一時テーブルに挿入し、そのテーブルを使用してカーソルを作成することもできます。
Declare @UserID varchar(100)
create table #users (UserID varchar(100))
declare @sqlstatement nvarchar(4000)
set @sqlstatement = 'Insert into #users (userID) SELECT userId FROM users'
exec(@sqlstatement)
declare users_cursor cursor for Select UserId from #Users
OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC asp_DoSomethingStoredProc @UserId
FETCH NEXT FROM users_cursor
INTO @UserId
END
CLOSE users_cursor
DEALLOCATE users_cursor
drop table #users
このコードは、@ STATEMENTで「+」を使用できないため、カーソルを持つ動的列の非常に良い例です。
ALTER PROCEDURE dbo.spTEST
AS
SET NOCOUNT ON
DECLARE @query NVARCHAR(4000) = N'' --DATA FILTER
DECLARE @inputList NVARCHAR(4000) = ''
DECLARE @field sysname = '' --COLUMN NAME
DECLARE @my_cur CURSOR
EXECUTE SP_EXECUTESQL
N'SET @my_cur = CURSOR FAST_FORWARD FOR
SELECT
CASE @field
WHEN ''fn'' then fn
WHEN ''n_family_name'' then n_family_name
END
FROM
dbo.vCard
WHERE
CASE @field
WHEN ''fn'' then fn
WHEN ''n_family_name'' then n_family_name
END
LIKE ''%''+@query+''%'';
OPEN @my_cur;',
N'@field sysname, @query NVARCHAR(4000), @my_cur CURSOR OUTPUT',
@field = @field,
@query = @query,
@my_cur = @my_cur OUTPUT
FETCH NEXT FROM @my_cur INTO @inputList
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @inputList
FETCH NEXT FROM @my_cur INTO @inputList
END
RETURN
ODBC接続を介した非リレーショナルデータベース(IDMS誰か?).
select * from a where a=1 and b in (1,2)
応答に45分かかりますが、in句なしでキーセットを使用するように書き換えると、1秒未満で実行されます。
select * from a where (a=1 and b=1)
union all
select * from a where (a=1 and b=2)
列Bのinステートメントに1145行が含まれる場合、カーソルを使用して個々のステートメントを作成し、動的SQLとして実行する方が、in句を使用するよりもはるかに高速です。愚かなねえ?
はい、リレーショナルデータベースでは、カーソルを使用する時間はありません。カーソルループが数倍速いインスタンスに出会ったとは信じられません。
まず、可能な限りカーソルの使用を避けます。これがなければできないと思われるときに、それを根絶するためのいくつかのリソースがあります:
カーソルを失うには15の方法が必要です...パート1、はじめに
とはいえ、結局のところ、1つにとどまっている可能性があります。これらのいずれかが当てはまることを確認するには、質問から十分に知りません。その場合、別の問題が発生します。カーソルの選択ステートメントは、EXECUTEステートメントではなく、actualSELECTステートメントでなければなりません。あなたが立ち往生しています。
しかし、一時テーブルの使用に関するcmsjr(私が書いている間に入った)からの回答を参照してください。私はglobalカーソルを "プレーン"カーソルよりももっと避けたいです。
最近、OracleからSQL Serverに切り替えた後(雇用者の好み)、SQL Serverでのカーソルサポートが遅れています。カーソルは、常に邪悪であるとは限らず、最適化のヒントを再配置または追加して複雑なクエリを調整しようとするよりも、必要とされることもあります。 「カーソルは悪である」という意見は、SQL Serverコミュニティではるかに顕著です。
したがって、この答えはOracleに切り替えるか、MSに手がかりを与えることだと思います。
for
暗黙のループカーソルの定義/オープン/クローズ!)あなたと共有したい別の例があります
:D http://www.sommarskog.se/dynamic_sql.html#cursor
SQL Serverのもう1つのオプションは、ストアドプロシージャ内のテーブル変数にすべての動的クエリを実行し、カーソルを使用してクエリと処理を行うことです。恐ろしいカーソルの議論について:)、私はいくつかの状況で、適切に設定すればカーソルが実際により速くなることを示す研究を見てきました。必要なクエリが複雑すぎる場合、または人間にとって(私にとっては;))不可能な場合に自分で使用します。