2013-10-10 13 views
5

ho una query di grandi dimensioni in Firebird (che ho eseguito utilizzando FlameRobin), utilizzando un parametro in tutto il luogo, ma ottenere la query seguente per eseguire lo farà:Definire variabili ed eseguire una query utilizzando EXECUTE BLOCK

SELECT * FROM customers WHERE customerid = 1234; 

Voglio definire 1234 come variabile, ad esempio customerID, in modo che possa facilmente sostituirlo con qualcos'altro.

Ho imparato che ho bisogno di mettere questo all'interno di un EXECUTE BLOCK.

EXECUTE BLOCK 
AS 
DECLARE customerID INT = 1234; 

BEGIN 
    SELECT * FROM customers WHERE customerid = :customerID 
END 

Se di qualche importanza, l'errore che sto ottenendo è Engine Message : Dynamic SQL Error SQL error code = -104 Unexpected end of command - line 3, column 26

risposta

10

Il problema è che FlameRobin ha bisogno di sapere quando un'istruzione finisce e inizia l'istruzione successiva. Per impostazione predefinita usa il punto e virgola (;) per questo. Tuttavia uno EXECUTE BLOCK è essenzialmente una stored procedure che non è archiviata nel database, quindi contiene il codice PSQL che utilizza anche il punto e virgola come separatore di istruzioni.

La conseguenza di ciò è che si verificano errori di sintassi poiché FlameRobin invia istruzioni incomplete al server (ovvero: invia una dichiarazione dopo ogni ; che incontra).

È necessario istruire FlameRobin per utilizzare un terminatore di istruzioni diverso utilizzando SET TERM. Anche altri strumenti di query di Firebird (ad esempio isql) richiedono questo, ma in realtà non fa parte della sintassi stessa di Firebird!

quindi è necessario eseguire il codice come:

-- Instruct flamerobin to use # as the terminator 
SET TERM #; 
EXECUTE BLOCK 
AS 
DECLARE customerID INT = 1234; 

BEGIN 
    SELECT * FROM customers WHERE customerid = :customerID; 
END# 
-- Restore terminator to ; 
SET TERM ;# 

Tuttavia questo modo sarà ancora generato un errore, perché questa query non è valida per PSQL: Un SELECT in un blocco PSQL richiede una clausola INTO per mappare le colonne alle variabili. E per ottenere i valori fuori dalla EXECUTE BLOCK tornato a FlameRobin è inoltre necessario specificare una clausola di RETURNS come descritto nella documentation of EXECUTE BLOCK:

-- Instruct flamerobin to use # as the terminator 
SET TERM #; 
EXECUTE BLOCK 
    RETURNS (col1 INTEGER, col2 VARCHAR(100)) 
AS 
DECLARE customerID INT = 1234; 

BEGIN 
    SELECT col1, col2 FROM customers WHERE customerid = :customerID INTO :col1, :col2; 
    SUSPEND; 
END# 
-- Restore terminator to ; 
SET TERM ;# 

Per quanto ne so il SUSPEND non è tecnicamente necessario qui, ma FlameRobin non lo farà recupera la riga restituita se non è inclusa.

Tuttavia, quanto sopra non funzionerà se la selezione produce più righe. Per questo è necessario utilizzare FOR SELECT ... DO combinato con un SUSPEND:

-- Instruct flamerobin to use # as the terminator 
SET TERM #; 
EXECUTE BLOCK 
    RETURNS (col1 INTEGER, col2 VARCHAR(100)) 
AS 
DECLARE customerID INT = 1234; 

BEGIN 
    FOR SELECT col1, col2 FROM customers WHERE customerid = :customerID INTO :col1, :col2 
    DO 
    SUSPEND; 
END# 
-- Restore terminator to ; 
SET TERM ;# 

Il SUSPEND qui restituisce la riga e aspetta fino a quando il chiamante ha recuperato quella riga e poi prosegue con il ciclo FOR. In questo modo itererà sui risultati.

IMHO questo troppo sforzo per la parametrizzazione. Potresti considerare semplicemente di non parametrizzare quando usi flamerobin, o usare uno strumento che supporti la richiesta di valori di parametro per i normali segnaposti dei parametri di Firebird (ma per essere onesti non sono sicuro che ce ne siano).

+0

I tuoi campioni funzionano perfettamente. Grazie per la risposta.È davvero troppo sforzo implementarlo, dovrei cambiare molte domande. Ma almeno so di conoscere la porta sbagliata. –

-2
SET TERM #; 
EXECUTE BLOCK 
RETURNS (COL1 Varchar(5) , COL2 INTEGER , COL3 INTEGER) 
AS 
DECLARE customerID INT = 5; 
BEGIN 
    FOR SELECT COSP.OSP_COMPON,COSP.OSP_DIAS FROM COSP WHERE COSP.OSP_ORDEM=2 INTO COL1 , COL3 
    DO 
    FOR SELECT CMES.MESNUM FROM CMES WHERE CMES.MESNUM = customerID INTO COL2 DO SUSPEND; 
    SUSPEND; 
END# 
SET TERM ;# 

perché in autunno?

Problemi correlati