Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 12.0.1 (Deutsch) » SQL Anywhere Server - SQL-Benutzerhandbuch » Gespeicherte Prozeduren, Trigger, Batches und benutzerdefinierte Funktionen

 

EXECUTE IMMEDIATE in Prozeduren, Triggern, benutzerdefinierten Funktionen und Batches

Die EXECUTE IMMEDIATE-Anweisung ermöglicht den Aufbau von Anweisungen mit einer Kombination aus Literalzeichenfolgen (in Apostrophen) und Variablen. Beispiel: Die folgende Prozedur enthält eine EXECUTE IMMEDIATE-Anweisung, die eine Tabelle erstellt.

CREATE PROCEDURE CreateTableProcedure(
      IN tablename CHAR(128) )
BEGIN
   EXECUTE IMMEDIATE 'CREATE TABLE '
   || tablename
   || '( column1 INT PRIMARY KEY )'
END;

Die EXECUTE IMMEDIATE-Anweisung kann mit Abfragen verwendet werden, die Ergebnismengen zurückgeben. Verwenden Sie die Klausel WITH RESULT SET ON mit der EXECUTE IMMEDIATE-Anweisung, um anzuzeigen, dass die Anweisung eine Ergebnismenge zurückgibt. Das Standardverhalten ist, dass die Anweisung keine Ergebnismenge zurückgibt. Das Angeben von WITH RESULT SET ON oder WITH RESULT SET OFF wirkt sich sowohl darauf aus, was passiert, wenn die Prozedur erstellt wird, als auch darauf, was passiert, wenn die Prozedur ausgeführt wird.

Betrachten Sie die folgende Prozedur:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 'SELECT 1';
END;

Obwohl die Definition der Prozedur keine RESULT SET-Klausel enthält, versucht der Datenbankserver zu ermitteln, ob die Prozedur eine solche generiert. Hier gibt die EXECUTE IMMEDIATE-Anweisung an, dass keine Ergebnismenge generiert wird. Daher definiert der Datenbankserver die Prozedur ohne Ergebnismengenspalten und in der SYSPROCPARM-Systemansicht für diese Prozedur sind keine Zeilen vorhanden. Ein DESCRIBE für eine CALL-Anweisung für diese Prozedur würde keine Ergebnisspalten zurückgeben. Wenn eine Embedded SQL-Anwendung diese Informationen verwendet, um zu entscheiden, ob sie einen Cursor öffnet oder die Anweisung ausführt, wird die Anweisung ausgeführt und dann ein Fehler zurückgegeben.

Das zweite Beispiel ist eine modifizierte Version der obigen Prozedur:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET ON 'SELECT 1';
END;

Hier bewirkt die WITH RESULT SET ON-Klausel, dass in der SYSPROCPARM-Systemansicht eine Zeile für diese Prozedur vorhanden ist. Der Datenbankserver weiß nicht, wie die Ergebnismenge aussieht, weil die Prozedur EXECUTE IMMEDIATE verwendet, aber er weiß, dass eine erwartet wird. Deshalb definiert der Datenbankserver in SYSPROCPARM eine Platzhalter-Ergebnismengenspalte mit dem Namen "expression" und dem SMALLINT-Datentyp, um dies anzuzeigen. Beachten Sie, dass nur eine Platzhalter-Ergebnismengenspalte erstellt wird. Der Server hat keine Möglichkeit, die Anzahl und den Typ der einzelnen Ergebnismengenspalten zu ermitteln, wenn eine EXECUTE IMMEDIATE-Anweisung verwendet wird. Betrachten Sie daher dieses leicht geänderte Beispiel:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET ON 'SELECT 1, 2, 3';
END;

Hier gibt zwar die SELECT-Anweisung eine Ergebnismenge aus drei Spalten zurück, aber der Server platziert trotzdem nur eine Zeile in der SYSPROCPARM-Systemansicht. Daher schlägt die folgende Abfrage mit SQLCODE -866 fehl:

SELECT * FROM test_result_clause();

Dies liegt daran, dass die Merkmale der Ergebnismenge zum Zeitpunkt der Ausführung nicht mit dem Platzhalter-Ergebnis in SYSPROCPARM übereinstimmen.

Um die oben genannte Abfrage auszuführen, können Sie explizit die Namen und Typen der Spalten in der Ergebnismenge angeben, und zwar folgendermaßen:

SELECT * FROM test_result_clause() WITH (x INTEGER, y INTEGER, z INTEGER);

Wenn WITH RESULT SET ON angegeben ist, verarbeitet der Datenbankserver während der Ausführung eine EXECUTE IMMEDIATE-Anweisung, die eine Ergebnismenge zurückgibt. Wenn jedoch WITH RESULT SET OFF angegeben ist oder die Klausel nicht vorhanden ist, prüft der Datenbankserver dennoch den Typ der ersten Anweisung im syntaktisch analysierten Zeichenfolgenargument. Wenn diese Anweisung eine SELECT-Anweisung ist, gibt er eine Ergebnismenge zurück. Daher gilt im zweiten Beispiel oben:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 'SELECT 1';
END;

Diese Prozedur kann über Interactive SQL aufgerufen werden. Sie können allerdings die Prozedur so ändern, dass sie einen Batch enthält und keine einzelne SELECT-Anweisung:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 
    'begin declare v int; set v=1; select v; end';
END;

Dann wird bei einer CALL-Anweisung für die test_result_clause-Systemprozedur ein Fehler zurückgegeben (SQLCODE-946, SQLSTATE 09W03).

Dieses letzte Beispiel zeigt, wie es möglich ist, eine SELECT-Anweisung als Argument einer EXECUTE IMMEDIATE-Anweisung in einer Prozedur zu erstellen und die Prozedur eine Ergebnismenge zurückgeben zu lassen.



CREATE PROCEDURE DynamicResult(
   IN Columns LONG VARCHAR,
   IN TableName CHAR(128),
   IN Restriction LONG VARCHAR DEFAULT NULL )
BEGIN
    DECLARE Command LONG VARCHAR;
    SET Command = 'SELECT ' || Columns || ' FROM ' || TableName;
    IF ISNULL( Restriction,'') <> '' THEN
         SET Command = Command || ' WHERE ' || Restriction;
    END IF;
    EXECUTE IMMEDIATE WITH RESULT SET ON Command;
END;

Außerdem kann die Prozedur oben folgendermaßen aufgerufen werden:

CALL DynamicResult(
   'table_id,table_name',
   'SYSTAB',
   'table_id <= 10');

Dies liefert folgendes Ergebnis:

table_id table_name
1 ISYSTAB
2 ISYSTABCOL
3 ISYSIDX
... ...

Die oben angegebene CALL-Anweisung gibt korrekt eine Ergebnismenge zurück, obwohl in der Prozedur EXECUTE IMMEDIATE verwendet wird. Einige Server-APIs, wie ODBC, verwenden die kombinierte Anforderung PREPARE-DESCRIBE-EXECUTE-OR-OPEN, mit der die Anweisung entweder ausgeführt oder geöffnet wird, je nachdem, ob eine Ergebnismenge zurückgegeben wurde. Sollte die Anweisung geöffnet werden, kann die API oder Anwendung anschließend eine DESCRIBE CURSOR-Anweisung ausgeben, um zu ermitteln, wie die tatsächliche Ergebnismenge aussehen wird, statt sich auf den Inhalt der SYSPROCPARM-Systemansicht zu verlassen, der beim Erstellen der Prozedur festgelegt wurde. Sowohl DBISQL als auch DBISQLC verwenden diese Methode. In diesen Fällen kann eine CALL-Anweisung für die oben genannte Prozedur ohne Fehler ausgeführt werden. Anwendungsschnittstellen, die sich auf die DESCRIBE-Ergebnisse der Anweisung verlassen, können jedoch keine beliebige Anweisung verarbeiten.

In atomaren zusammengesetzten Anweisungen können Sie EXECUTE IMMEDIATE-Anweisungen nicht verwenden, die ein COMMIT verursachen, da COMMIT in diesem Kontext nicht zulässig ist.

 Siehe auch