2015-11-28 13 views
5

Sto cercando di creare una tabella temporanea nella stored procedure nel database di Firebird.Perché la tabella temporanea non è consentita nella stored procedure in Firebird?

mio immagazzinata lista procedure:

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 ;^

Ogni volta che sto cercando di creare questa procedura sto ottenendo l'errore:

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


Total execution time: 0.015s 

Quello che sto facendo male? Firebird 3.0 RC

Grazie in anticipo Robert

risposta

3

Firebird doesn Ti permettono di usare DDL all'interno delle stored procedure, quindiLe istruzioninon sono consentite in PSQL. Come indicato nello answer by lad2025, è possibile aggirare questa limitazione utilizzando EXECUTE STATEMENT.

Tuttavia, l'idea alla base di un global temporary table è che lo si crea una volta e continuano a esistere in modo che possano essere utilizzati in seguito. I dati sono visibili solo alla connessione che ha creato i dati e i dati vengono cancellati dopo il commit della transazione (ON COMMIT DELETE ROWS) o la chiusura della connessione (ON COMMIT PRESERVE ROWS) in base al tipo di tabella temporanea globale.

l'aggiornamento di riferimento lingua:

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.

Così, invece di cercare di creare la tabella temporanea globale all'interno della vostra stored procedure, prima lo crea, quindi creare la stored procedure che utilizza GTT già definito.

+0

Questo è il punto, dopo un po 'di tempo in difficoltà su questo problema penso anche che sia la soluzione migliore, grazie! – robsonwk

2

Da 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.

È possibile utilizzare Dynamic-SQL e avvolgere il codice con EXECUTE STATEMENT come soluzione alternativa:

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

Grazie per il suggerimento, tuttavia sto ricevendo errore "Errore SQL dinamico Codice errore SQL = -204 Tabella sconosciuta TEMP_FUNDS". C'è in alternativa Firebird alla tabella temporanea per mantenere le righe temporanee per un breve periodo? – robsonwk

+0

@robsonwk È necessario includere tutte le istruzioni. Non solo creazione. Sei stato tu? – lad2025

+1

@robsonwk Gli oggetti utilizzati direttamente nelle stored procedure devono esistere al momento della creazione. Si noti inoltre che le tabelle create in una transazione non possono essere utilizzate in DML nella stessa transazione. Pertanto, se si desidera utilizzare questa soluzione di istruzione di esecuzione, è necessario utilizzare SQL dinamico utilizzando l'istruzione execute 'with autonomous transaction' per la creazione GTT ** e ** per DML. Ti suggerisco di non farlo. –

0

Giusto per approfondire le altre risposte sopra corrette, io uso le tabelle temporanee per lo più per problemi di prestazioni, come quando ho un sottoinsieme parametrizzato di dati che devono essere query su un insieme più ampio come:

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

dove GTT $ IDS è popolato con il sottoinsieme di ID.

A volte, per le procedure estremamente complesse, devo utilizzare più tabelle temporanee, così li ho creare nei metadati (al di fuori di dichiarazioni PSQL, ovviamente) in questo modo:

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 
... 

facendo questo può essere semplicistico per alcuni SQLer avanzati là fuori, ma ha più senso per me (trasportare la tecnica dai miei giorni dBase/VFP) ed è super veloce rispetto a un mucchio di join complessi.

Non ho mai avuto il tempo di imparare come utilizzare la clausola "PLAN" (o farlo funzionare correttamente), quindi in pratica utilizzo questa tecnica per generare il PLAN tramite codice quando ottengo query lente, se questo ha senso .