2015-11-28 3 views
5

Ich versuche, temporäre Tabelle in gespeicherten Prozedur in Firebird-Datenbank zu erstellen.Warum temporäre Tabelle in gespeicherten Prozedur in Firebird nicht zulässig ist?

Meine gespeicherten Prozedur Eintrag:

SET TERM^; 

CREATE PROCEDURE initNATIONALHEALTHFUNDS 

AS BEGIN 

    CREATE GLOBAL TEMPORARY TABLE temp_FUNDS 
    (
    NATIONALHEALTHFUNDID Integer NOT NULL, 
    NAME Varchar(128) NOT NULL, 
    CODE Integer NOT NULL 
) 
    ON COMMIT PRESERVE ROWS; 
    commit; 

INSERT INTO tempFUNDS (NATIONALHEALTHFUNDID, CODE, NAME) VALUES (01 ,01 , 'Some Foundation'); 


    MERGE INTO NATIONALHEALTHFUNDS AS target 
    USING tempFUNDS AS source 
    ON target.NATIONALHEALTHFUNDID = source.NATIONALHEALTHFUNDID 
    WHEN NOT MATCHED THEN 
    INSERT (NATIONALHEALTHFUNDID, CODE, NAME) VALUES (source.NATIONALHEALTHFUNDID, source.CODE, source.NAME); 

    drop TABLE tempFUNDS; 
END^ 

SET TERM ;^

Jedes Mal, ich versuche dieses Verfahren schaffe ich Störung erhalte:

Engine Code : 335544569 
Engine Message : 
Dynamic SQL Error 
SQL error code = -104 
Token unknown - line 7, column 3 
CREATE 


Total execution time: 0.015s 

Was mache ich falsch? Firebird 3.0 RC

Vielen Dank im Voraus Robert

Antwort

3

Firebird doesn Ich darf nicht DDL in gespeicherten Prozeduren verwenden, also CREATE Anweisungen sind in PSQL nicht zulässig. Wie in der answer by lad2025 angegeben, können Sie diese Einschränkung umgehen, indem Sie EXECUTE STATEMENT verwenden.

Die Idee hinter einem global temporary table ist jedoch, dass Sie es einmal erstellen, und sie existieren weiterhin, damit sie später verwendet werden können. Die Daten sind nur für die Verbindung sichtbar, die die Daten erstellt hat, und die Daten werden nach dem Festschreiben der Transaktion (ON COMMIT DELETE ROWS) oder dem Schließen der Verbindung (ON COMMIT PRESERVE ROWS) abhängig vom Typ der globalen temporären Tabelle gelöscht.

Aus der Sprache Referenz Update:

Global temporary tables have persistent metadata, but their contents are transaction-bound (the default) or connection-bound. Every transaction or connection has its own private instance of a GTT, isolated from all the others. Instances are only created if and when the GTT is referenced, and destroyed upon transaction end or disconnection.

Also anstatt zu versuchen, die globale temporäre Tabelle in Ihrer gespeicherten Prozedur zu erstellen, erstellen Sie es zuerst, dann die gespeicherte Prozedur erstellen, die die bereits definierte GTT verwendet.

+0

Dies ist der Punkt, nach einiger Zeit kämpft über dieses Problem, ich denke auch, es ist die beste Lösung, Danke! – robsonwk

2

Von GTT documentation:

CREATE GLOBAL TEMPORARY TABLE

is a regular DDL statement that is processed by the engine the same way as a CREATE TABLE statement is processed. Accordingly, it not possible to create or drop a GTT within a stored procedure or trigger.

Sie Dynamic-SQL verwenden können, und wickeln Sie Ihren Code mit EXECUTE STATEMENT als Abhilfe:

SET TERM^; 

CREATE PROCEDURE initNATIONALHEALTHFUNDS 
AS BEGIN 

EXECUTE STATEMENT 
    'CREATE GLOBAL TEMPORARY TABLE temp_FUNDS 
    (
    NATIONALHEALTHFUNDID Integer NOT NULL, 
    NAME Varchar(128) NOT NULL, 
    CODE Integer NOT NULL 
) 
    ON COMMIT PRESERVE ROWS; 
    commit;'; 

... 

END^ 
+0

Vielen Dank für Hinweis, aber ich bekomme Fehler "Dynamic SQL Fehler SQL Fehlercode = -204 Tabelle unbekannt TEMP_FUNDS". Gibt es in Firebird eine Alternative zur temporären Tabelle, um temporäre Zeilen für kurze Zeit zu behalten? – robsonwk

+0

@robsonwk Sie müssen jede Anweisung umbrechen. Nicht nur Schöpfung. Hast du das gemacht? – lad2025

+1

@robsonwk Objekte, die direkt in gespeicherten Prozeduren verwendet werden, müssen zum Zeitpunkt der Erstellung vorhanden sein. Beachten Sie außerdem, dass in einer Transaktion erstellte Tabellen in derselben Transaktion nicht in DML verwendet werden können. Wenn Sie also diese Execution-Statement-Lösung verwenden möchten, müssen Sie dynamisches SQL verwenden, indem Sie die Anweisung execute mit autonomer Transaktion für die GTT-Erstellung ** und ** für die DML ausführen. Ich schlage vor, dass du das nicht tust. –

0

einfach auf den anderen oben richtigen Antworten zu erarbeiten, verwende ich temporäre Tabellen meist für Performance-Probleme, wie wenn ich eine parametrisierte Teilmenge von Daten, die Abfrage für einen größeren Satz wie sein muss:

select * from MAIN_TABLE 
    where MAIN_TABLE.ID in (select ID from GTT$IDS) 

wo GTT $ IDS mit der Teilmenge von IDs gefüllt ist.

Manchmal für hochkomplexe Verfahren, muss ich mehrere temporäre Tabellen verwenden, so schaffe ich sie in den Metadaten (außerhalb von PSQL Aussagen, natürlich) wie folgt:

create global temporary table GTT$IDS_1 (INT1 integer, INT2 integer); 
create index IDX_GTT$IDS_11 on GTT$IDS_1 (INT1); 
create index IDX_GTT$IDS_12 on GTT$IDS_1 (INT2); 

create global temporary table GTT$IDS_2 
... 

create global temporary table GTT$IDS_3 
... 

dies tun simpel sein kann für einige fortgeschrittene SQL'er da draußen, aber es macht für mich am meisten Sinn (Übertragungstechnik aus meinen dBase/VFP-Tagen) und es ist super schnell im Vergleich zu einer Menge komplexer Joins.

Ich habe mir nie wirklich die Zeit genommen zu lernen, wie man die 'PLAN' -Klausel benutzt (oder es richtig funktioniert), also verwende ich diese Technik, um den PLAN über Code zu generieren, wenn ich langsame Abfragen bekomme, wenn das Sinn macht .

Verwandte Themen