Domanda

Devo usare l'esecuzione dinamica di SQL su Oracle dove non conosco il numero esatto di variabili di bind utilizzate in SQL prima del runtime.

Esiste un modo per utilizzare in qualche modo un numero variabile di variabili di bind nella chiamata per EXECUTE IMMEDIATE ?

Più specificamente, devo passare un parametro all'SQL sconosciuto ma non so con quale frequenza verrà utilizzato lì.

Ho provato qualcosa del genere

EXECUTE IMMEDIATE 'SELECT SYSDATE FROM DUAL WHERE :var = :var' USING 1;

Ma è tornato indietro con ORA-01008: non tutte le variabili associate.

È stato utile?

Soluzione

Non puoi farlo con EXECUTE IMMEDIATE . Tuttavia, puoi farlo utilizzando il pacchetto DBMS_SQL di Oracle. La Guida per gli sviluppatori di applicazioni di database ha un confronto tra i metodi EXECUTE IMMEDIATE che conosci e dbms_sql . Questa pagina documenti DBMS_SQL , ma ha alcuni esempi (collegati sopra) che dovrebbero iniziare (l'esempio 1 è un semplice caso di esecuzione di un'istruzione che potrebbe avere un numero arbitrario di variabili bind). DBMS_SQL è molto più ingombrante dal punto di vista della codifica, ma ti consentirà di fare qualsiasi cosa tu possa concepire.

Sono consentite più istanze della variabile bind che si verificano nell'SQL. Tuttavia, dovrai conoscere il nome utilizzato come variabile di bind (ad esempio: var nel tuo caso) per passarlo in DBMS_SQL.BIND_VARIABLE .

Altri suggerimenti

Puoi anche aggirare questo problema usando un'istruzione WITH . Generalmente usare DBMS_SQL è meglio, ma a volte questo è un modo più semplice:

BEGIN
    EXECUTE IMMEDIATE 'WITH var AS (SELECT :var FROM dual) SELECT SYSDATE FROM DUAL WHERE (SELECT * FROM var) = (SELECT * FROM var)' USING 1;
END;

Questo Discussione su AskTom tratta l'argomento in dettaglio.

Nel tuo caso se vuoi passare un parametro o nessuno, potresti creare due query che hanno un singolo parametro e in una di queste query non viene utilizzato (ovvero il predicato è sempre vero) in questo modo:

-- query1
SELECT * FROM DUAL WHERE dummy = :x;

-- query2
SELECT * FROM DUAL WHERE nvl(:x, 1) IS NOT NULL;

Probabilmente puoi affinare il predicato in modo che l'ottimizzatore capisca che è sempre vero.

  

Più specificamente, devo passare un parametro nell'SQL sconosciuto ma non so con quale frequenza verrà utilizzato lì.

In realtà ho riscontrato esattamente lo stesso problema un paio di giorni fa e un amico ha condiviso con me un modo per fare esattamente questo con EXECUTE IMMEDIATE .

Implica la generazione di un blocco PLSQL rispetto al blocco SQL stesso. Quando si utilizza EXECUTE IMMEDIATE con un blocco di codice PLSQL, è possibile associare le variabili per nome anziché semplicemente per posizione.

Guarda il mio esempio / codice e sul mio thread di domanda / risposta simile:

Si può usare dbms_sql come ha spiegato Steve Broberg ma il cursore risultante non può essere consumato (letto) in molti client. Oracle 11 ha aggiunto una funzione di conversione ( dbms_sql .to_refcursor ) che consente di convertire un cursore dbms_sql in un cursore ref ma per qualche motivo non è possibile utilizzare questo cursore ref convertito in un'applicazione .Net. Si può usare un normale cursore ref in .net ma non un cursore ref che era il cursore dbms_sql .

Quindi che tipo di client utilizzerà questo cursore?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top