Bereich der Transact-SQL-Cursornamen

Microsoft SQL Server unterstützt die Schlüsselwörter GLOBAL und LOCAL in der DECLARE CURSOR-Anweisung, um den Bereich des Cursornamens zu definieren. GLOBAL gibt an, dass der Cursorname für die Verbindung global ist. LOCAL gibt an, dass der Cursorname für die gespeicherte Prozedur, den Trigger oder den Batch, die bzw. der die DECLARE CURSOR-Anweisung enthält, lokal ist.

Vor Microsoft SQL Server Version 7.0 waren die Namen von Transact-SQL-Cursorn für die Verbindung global. Sie könnten eine gespeicherte Prozedur ausführen, die einen Cursor erstellt, und anschließend eine andere gespeicherte Prozedur aufrufen, die die Zeilen aus diesem Cursor abruft:

USE AdventureWorks2008R2;
GO
CREATE PROCEDURE OpenCrsr AS

DECLARE SampleCrsr CURSOR FOR
SELECT TOP (20)LastName
FROM Person.Person
WHERE LastName LIKE 'S%';

OPEN SampleCrsr;
GO

CREATE PROCEDURE ReadCrsr AS
FETCH NEXT FROM SampleCrsr
WHILE (@@FETCH_STATUS <> -1)
BEGIN
   FETCH NEXT FROM SampleCrsr
END
GO

EXEC OpenCrsr; /* DECLARES and OPENS SampleCrsr. */
GO
EXEC ReadCrsr; /* Fetches the rows from SampleCrsr. */
GO
CLOSE SampleCrsr;
GO
DEALLOCATE SampleCrsr;
GO

Lokale Cursor bieten Cursorn, die in gespeicherten Prozeduren und Triggern implementiert sind, umfangreichen Schutz. Auf globale Cursor kann von außerhalb der gespeicherten Prozedur oder dem Trigger, in der bzw. dem sie deklariert wurden, verwiesen werden. Folglich können sie versehentlich durch Anwendungen außerhalb der gespeicherten Prozedur oder des Triggers geändert werden. Lokale Cursor sind sicherer als globale Cursor, da es nicht möglich ist, außerhalb einer gespeicherten Prozedur auf sie zu verweisen, sofern sie nicht absichtlich als Cursorausgabeparameter an den Aufrufenden übergeben wurden.

Da außerhalb einer gespeicherten Prozedur oder eines Triggers auf globale Cursor verwiesen werden kann, können sie unbeabsichtigte Nebeneffekte aufweisen, die sich auf andere Anweisungen auswirken. Ein Beispiel hierfür wäre eine gespeicherte Prozedur, die einen globalen Cursor mit dem Namen xyz erstellt und den Cursor nach dem Beenden offen lässt. Der Versuch, einen anderen globalen Cursor mit dem Namen xyz nach dem Beenden der gespeicherten Prozedur zu erstellen, führt aufgrund des doppelten Namens zu einem Fehler.

Globale und lokale Cursor verfügen über getrennte Namespaces; dadurch ist das Vorhandensein eines globalen Cursors sowie eines lokalen Cursors mit demselben Namen zur gleichen Zeit möglich. Transact-SQL-Anweisungen, die einen Cursornamen als Parameter akzeptieren, unterstützen auch das Schlüsselwort GLOBAL, um den Gültigkeitsbereich des Namens zu identifizieren. Wenn GLOBAL fehlt und es sowohl einen lokalen als auch einen globalen Cursor mit dem Namen gibt, der im Parameter für Cursornamen angegeben ist, wird auf den lokalen Cursor verwiesen.

Die Datenbankoption CURSOR_DEFAULT, die mit der ALTER DATABASE-Anweisung festgelegt wird, steuert die Standardeinstellung, die von der DECLARE CURSOR-Anweisung verwendet wird, wenn weder LOCAL noch GLOBAL angegeben wurden. Der aktuelle Wert für diese Datenbankoption ist in der sys.databases-Katalogsicht gespeichert. Wenn der Wert in der local_cursor_default-Spalte in der sys.databases-Katalogsicht true ist, greifen die Transact-SQL-Cursor standardmäßig auf LOCAL zurück. Wenn die Option false ist, greifen die Transact-SQL-Cursor standardmäßig auf GLOBAL zurück. In SQL Server wird die Datenbankoption standardmäßig auf FALSE (GLOBAL) gesetzt, um eine Übereinstimmung mit dem Verhalten früherer Versionen von SQL Server zu erzielen.

Gespeicherte Prozeduren, die die Anweisungen DECLARE und OPEN für lokale Cursor ausführen, können die Cursor für die Verwendung durch die aufrufende gespeicherte Prozedur, den Trigger oder Batch übergeben. Dies erfolgt über einen OUTPUT-Parameter, der mithilfe des neuen CURSOR VARYING-Datentyps definiert wird. Cursorvariablen können nur als OUTPUT-Parameter verwendet werden. Sie können nicht für Eingabeparameter verwendet werden. Der Cursor muss geöffnet sein, wenn die gespeicherte Prozedur beendet wird, um in einem OUTPUT-Parameter zurückgegeben zu werden. Lokale Variablen können auch mit dem neuen CURSOR-Datentyp deklariert werden, um einen Verweis auf einen lokalen Cursor aufzunehmen.

USE AdventureWorks2008R2;
GO
/* Create a procedure with a cursor output parameter. */
CREATE PROCEDURE OpenCrsr @OutCrsr CURSOR VARYING OUTPUT AS

SET @OutCrsr = CURSOR FOR
SELECT TOP (20) LastName
FROM Person.Person
WHERE LastName LIKE 'S%';

OPEN @OutCrsr;
GO

/* Allocate a cursor variable. */
DECLARE @CrsrVar CURSOR;

/* Execute the procedure created earlier to fill
  the variable. */
EXEC OpenCrsr @OutCrsr = @CrsrVar OUTPUT;

/* Use the variable to fetch the rows from the cursor. */
FETCH NEXT FROM @CrsrVar
WHILE (@@FETCH_STATUS <> -1)
BEGIN
   FETCH NEXT FROM @CrsrVar
END;

CLOSE @CrsrVar;

DEALLOCATE @CrsrVar;
GO

Datenbank-APIs unterstützen keine Cursorausgabeparameter für gespeicherte Prozeduren. Eine gespeicherte Prozedur, die einen Cursorausgabeparameter enthält, kann nicht direkt von einer Datenbank-API-Funktion ausgeführt werden. Diese gespeicherten Prozeduren können nur von einer anderen gespeicherten Prozedur, einem Trigger oder einem Transact-SQL-Batch oder -Skript ausgeführt werden.

Ein globaler Cursor steht so lange zur Verfügung, bis seine Zuordnung explizit aufgehoben oder die Verbindung geschlossen wird. Die Zuordnung lokaler Cursor wird implizit aufgehoben, wenn die gespeicherte Prozedur, der Trigger oder Batch beendet wird, in der bzw. dem sie erstellt wurden, es sei denn, der Cursor wurde als Parameter wieder zurückgegeben. Die Zuordnung des lokalen Cursor wird dann implizit aufgehoben, wenn der Parameter oder die auf den Cursor verweisende Variable in dem Code, der die Prozedur aufrief, den Gültigkeitsbereich verlässt.