2010-01-28 11 views
23

Ho questa tabella:Come restituire un set di risultati/cursore da un blocco anonimo Oracle PL/SQL che esegue Dynamic SQL?

ALLITEMS 
--------------- 
ItemId | Areas 
--------------- 
1  | EAST 
2  | EAST 
3  | SOUTH 
4  | WEST 

Il DDL:

drop table allitems; 

Create Table Allitems(ItemId Int,areas Varchar2(20)); 
Insert Into Allitems(Itemid,Areas) Values(1,'east'); 
Insert Into Allitems(ItemId,areas) Values(2,'east'); 
insert into allitems(ItemId,areas) values(3,'south'); 
insert into allitems(ItemId,areas) values(4,'east'); 

In MSSQL, per ottenere un cursore da uno SQL dinamico che posso fare:

DECLARE @v_sqlStatement VARCHAR(2000); 
SET @v_Sqlstatement = 'SELECT * FROM ALLITEMS'; 
EXEC (@v_sqlStatement); --returns a resultset/cursor, just like calling SELECT 

In Oracle, ho è necessario utilizzare un blocco PL/SQL:

SET AUTOPRINT ON; 
DECLARE 
V_Sqlstatement Varchar2(2000); 
outputData SYS_REFCURSOR; 
BEGIN 
V_Sqlstatement := 'SELECT * FROM ALLITEMS'; 
OPEN outputData for v_Sqlstatement; 
End; 
--result is : anonymous block completed 

Ma tutto ciò che ottengo è "blocco anonimo completato".
Come ottengo per restituire il cursore?
(so che se faccio AUTOPRINT, si stamperà le informazioni nella refcursor (non è la stampa nel codice di cui sopra, ma questo è un altro problema))

sarò chiamata a questo SQL dinamico dal codice (ODBC, C++) e mi serve per restituire un cursore.
Come faccio a fare questo? Sono perplesso.

risposta

36

È possibile scrivere una funzione PL/SQL di restituire quel cursore (o si potrebbe mettere che la funzione in un pacchetto se avete più di codice relative a questo):

CREATE OR REPLACE FUNCTION get_allitems 
    RETURN SYS_REFCURSOR 
AS 
    my_cursor SYS_REFCURSOR; 
BEGIN 
    OPEN my_cursor FOR SELECT * FROM allitems; 
    RETURN my_cursor; 
END get_allitems; 

Ciò restituirà il cursore.

Assicurati di non mettere il tuo SELECT -Stringa tra virgolette in PL/SQL quando possibile. Inserirlo nelle stringhe significa che non può essere controllato in fase di compilazione e che deve essere analizzato ogni volta che lo si utilizza.


Se avete veramente bisogno di utilizzare SQL dinamico si può mettere la query tra virgolette singole:

OPEN my_cursor FOR 'SELECT * FROM allitems'; 

Questa stringa è da analizzare ogni volta che la funzione viene chiamata, che di solito è più lento e pelli errori nella tua query fino al runtime.

assicurarsi di utilizzare bind-variabili, ove possibile, da evitare hard parses:

OPEN my_cursor FOR 'SELECT * FROM allitems WHERE id = :id' USING my_id; 
+0

Grazie! Ci proverò. – Liao

+0

@Peter Lang: Come chiamereste la funzione in questo caso? – MissPiplup

+0

@MissPiplup: ho corretto il collegamento interrotto, ti aiuta? –

8

in SQL * Plus si potrebbe anche usare una variabile REFCURSOR:

SQL> VARIABLE x REFCURSOR 
SQL> DECLARE 
    2 V_Sqlstatement Varchar2(2000); 
    3 BEGIN 
    4 V_Sqlstatement := 'SELECT * FROM DUAL'; 
    5 OPEN :x for v_Sqlstatement; 
    6 End; 
    7/

ProcÚdure PL/SQL terminÚe avec succÞs. 

SQL> print x; 

D 
- 
X 
+0

Ma la "stampa x" restituisce un cursore? Ho bisogno di chiamare questo blocco PL/SQL dal codice C++ e quindi ho bisogno di restituire un cursore. O c'è un modo per accedere a "x" dal codice? – Liao

+0

@Liao: X è il cursore, dovresti essere in grado di accedervi come una variabile OUT se chiami il blocco PL/SQL da C++. 'print' tuttavia è un comando SQL * Plus e non funzionerà al di fuori di SQL * Plus. –

1

si dovrebbe essere in grado di dichiarare un cursore per essere una variabile di binding (chiamato parametri in altri DBMS)

come ha scritto Vincent, puoi fare qualcosa del genere:

begin 
    open :yourCursor 
    for 'SELECT "'|| :someField ||'" from yourTable where x = :y' 
     using :someFilterValue; 
end; 

Dovresti associare 3 vars a quello script. Una stringa di input per "someField", un valore per "someFilterValue" e un cursore per "yourCursor" che deve essere dichiarato come output var.

Sfortunatamente, non ho idea di come lo fareste dal C++.(Si potrebbe dire fortunatamente per me, però. ;-))

A seconda di quale libreria di accesso si utilizza, potrebbe essere un dolore reale o semplice.

-6

Questa impostazione deve essere impostata:

SET SERVEROUTPUT ON 
Problemi correlati