Frage

Ich habe eine dynamische SQL-Anweisung I in einer gespeicherten Prozedur erstellt haben. Ich brauche die Ergebnisse iterieren einen Cursor zu verwenden. Ich habe eine harte Zeit, um die richtige Syntax herauszufinden. Hier ist, was ich tue.

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

Was ist der richtige Weg, dies zu tun?

War es hilfreich?

Lösung

Ein Cursor wird nur eine select-Anweisung übernehmen, so dass, wenn die SQL wirklich den declare cursor Teil der Anweisung, die Sie ausführen muss dynamisch sein machen. Für die unter Ihrem Server arbeiten mit globalen Cursor sein müssen.

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

Wenn Sie mit den globalen Cursor vermeiden müssen, könnten Sie auch die Ergebnisse Ihrer dynamischen SQL in eine temporäre Tabelle einfügen, und verwenden Sie dann die Tabelle Sie den Cursor zu füllen.

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

Andere Tipps

Dieser Code ist ein sehr gutes Beispiel für eine dynamische Spalte mit einem Cursor, da Sie nicht ‚+‘ in @STATEMENT verwenden können:

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

Arbeiten mit einer nicht-relationalen Datenbank (IDMS anyone?) Über eine ODBC-Verbindung gilt als eine jener Zeiten, in denen Cursor und dynamische SQL den einzigen Weg zu sein scheinen.

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

dauert 45 Minuten zu reagieren, während neu geschrieben Keysets zu verwenden, ohne die in Klausel unter 1 laufen in der zweiten:

select * from a where (a=1 and b=1)
union all
select * from a where (a=1 and b=2)

Wenn die in Anweisung für die Spalte B 1145 Zeilen enthält, einen Cursor zu verwenden indidivudal Anweisungen zu erstellen und führen sie als dynamischer SQL ist weit schneller als die Verwendung von in-Klausel. Dumme hey?

Und ja, es gibt keine Zeit in einer relationalen Datenbank, die Cursors verwendet werden soll. Ich kann einfach nicht glauben, dass ich auf eine Instanz gekommen sind, wo ein Cursor Schleife um mehrere Größenordnungen schneller ist.

Zunächst einmal, vermeiden einen Cursor zu verwenden, wenn überhaupt möglich. Hier sind einige Ressourcen für die Verwurzelung es aus, wenn es scheint, dass Sie nicht ohne tun können:

There Must 15 Möglichkeiten, Ihre Cursors zu verlieren ... Teil 1, Einführung

Zeile-für-Zeile Verarbeitung ohne Cursor

Wie gesagt, obwohl, können Sie mit einer schließlich stecken - ich weiß nicht genug von Ihrer Frage sicher sein, dass entweder die gelten. Wenn das der Fall ist, haben Sie ein anderes Problem bekommen - die select-Anweisung für den Cursor muss eine ist SELECT-Anweisung, eine nicht-Anweisung ausführen. Sie sind fest.

Aber siehe die Antwort von cmsjr (die kamen, während ich mit dem Schreiben wurde) über eine temporäre Tabelle. Ich würde vermeiden global Cursor noch mehr als "plain" Einsen ....

Nach dem vor kurzem von Oracle auf SQL Server schaltend (Arbeitgeber Präferenz), bemerke ich Cursor-Unterstützung in SQL Server hinkt. Cursor sind nicht immer böse, manchmal erforderlich, manchmal viel schneller und manchmal sauberer als durch eine komplexe Abfrage zu optimieren versuchen, neu arrangieren oder Optimierungshinweise hinzufügen. Die "Cursor sind böse" Meinung ist viel mehr prominent in der SQL Server-Community.

Also habe ich diese Antwort erraten ist zu Oracle wechseln oder geben MS einen Anhaltspunkt.

Es ist ein weiteres Beispiel, das Ich mag würde mit Ihnen teilen
: D http://www.sommarskog.se/dynamic_sql.html#cursor0

Eine weitere Option in SQL Server ist, alle Ihre dynamischen Abfragen in Tabelle Variable in einer gespeicherten proc zu tun, verwenden Sie einen Cursor, abzufragen und zu verarbeiten. In Bezug auf die gefürchtete Cursor Debatte :) habe ich Studien gesehen, die in einigen Situationen zeigen, dass tatsächlich ein Cursor schneller sein kann, wenn richtig eingerichtet. Ich benutze sich selbst, wenn die erforderliche Abfrage zu komplex ist, oder einfach nicht menschlich (für mich;).) Möglich

Dieser Code kann für Sie nützlich sein.

Beispiel für Cursor-Verwendung in 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 
      ...
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top