50

ストアドプロシージャで作成した動的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

これを行う正しい方法は何ですか?

4

8 に答える 8

125

カーソルは選択ステートメントのみを受け入れるため、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
于 2009-06-25T20:01:02.910 に答える
21

@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
于 2011-07-07T19:42:08.607 に答える
4

ODBC 接続を介して非リレーショナル データベース (IDMS の誰か?) を操作することは、カーソルと動的 SQL が唯一のルートと思われる場合の 1 つとして認められます。

select * from a where a=1 and b in (1,2)

in 句なしでキーセットを使用するように書き直されている間、応答に 45 分かかりますが、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 句を使用するよりもはるかに高速になります。ばかねえ?

はい、リレーショナル データベースでは、カーソルを使用する必要はありません。カーソルループが数倍速いインスタンスに出くわしたとは信じられません。

于 2010-09-22T21:44:41.183 に答える
3

あなたと共有したい別の例があります
:D http://www.sommarskog.se/dynamic_sql.html#cursor0

于 2011-07-07T15:19:33.107 に答える
3

まず、カーソルの使用はできるだけ避けてください。これなしではいられないように思われる場合に、根絶するためのいくつかのリソースを次に示します。

カーソルを失う 15 の方法があるはずです... パート 1、はじめに

カーソルを使用しない行ごとの処理

とはいえ、結局のところ、あなたは 1 つで行き詰まっているかもしれません。私はあなたの質問から、それらのいずれかが当てはまるかどうかを確認するのに十分な知識がありません。その場合は、別の問題があります。カーソルの選択ステートメントは、EXECUTE ステートメントではなく、実際のSELECT ステートメントでなければなりません。あなたは立ち往生しています。

ただし、一時テーブルの使用に関する cmsjr (私が書いているときに入ってきた) からの回答を参照してください。「プレーンな」カーソルよりもグローバルカーソルを避けたいと思います....

于 2009-06-25T20:12:42.670 に答える
1

最近 Oracle から SQL Server に切り替えた後 (雇用主の好み)、SQL Server でのカーソルのサポートが遅れていることに気付きました。カーソルは常に悪いわけではなく、必要な場合もあれば、最適化のヒントを再配置または追加して複雑なクエリを調整しようとするよりもはるかに高速で、クリーンな場合もあります。SQL Server コミュニティでは、"カーソルは悪" という意見の方がはるかに顕著です。

したがって、この答えは、Oracleに切り替えるか、MSに手がかりを与えることだと思います。

于 2011-05-24T16:14:31.020 に答える
-3

このコードは役に立ちます。

SQL Server でのカーソルの使用例

DECLARE sampleCursor CURSOR FOR 
      SELECT K.Id FROM TableA K WHERE ....;
OPEN sampleCursor
FETCH NEXT FROM sampleCursor INTO @Id
WHILE @@FETCH_STATUS <> -1
BEGIN

UPDATE TableB
   SET 
      ...
于 2012-11-30T08:37:16.647 に答える