2009-06-17 13 views
9

Ho bisogno di utilizzare l'esecuzione dinamica di SQL su Oracle, dove non conosco il numero esatto di variabili di bind utilizzate in SQL prima del runtime.Oracle ESEGUI IMMEDIATO con un numero variabile di associazioni possibili?

C'è un modo per utilizzare un numero variabile di variabili di bind nella chiamata a EXECUTE IMMEDIATE in qualche modo?

In particolare, devo passare il parametro uno nello SQL sconosciuto ma non so con quale frequenza verrà utilizzato lì.

ho provato qualcosa di simile

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

Ma gettò indietro con ORA-01008: not all variables bound.

+0

correlati: [Perché non è possibile utilizzare le variabili di bind in DDL/istruzioni SCL in SQL dinamico? ] (http://stackoverflow.com/q/25489002/1461424) – Krumia

risposta

9

Non è possibile farlo con EXECUTE IMMEDIATE. Tuttavia, è possibile farlo utilizzando il pacchetto Oracle DBMS_SQL. Lo Database Application Developer's Guide ha un confronto tra lo EXECUTE IMMEDIATE che conosci e i metodi dbms_sql. This page 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 di binding). DBMS_SQL è molto più ingombrante dal punto di vista del codice, ma ti permetterà di fare qualsiasi cosa tu possa concepire.

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

2

Questa Thread on AskTom tratta l'argomento in dettaglio.

Nel tuo caso, se si desidera passare un parametro o nessuno, si potrebbe costruire due query che hanno un singolo parametro e in uno di questi interrogazione non viene utilizzato (vale a dire il predicato è sempre vero) come questo:

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

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

Probabilmente è possibile perfezionare il predicato in modo che l'ottimizzatore capisca che è sempre vero.

+0

Il problema è che le istruzioni SELECT in ingresso non sono note tranne che un singolo parametro (un ID) viene utilizzato almeno una volta o anche più volte. Il numero di legature non è noto. – Kosi2801

+0

Dovrai usare dbms_sql se il numero di parametri è sconosciuto –

1

Si può usare dbms_sql come spiegato da 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 di riferimento, ma per qualche motivo non è possibile utilizzare il cursore di riferimento convertito in un'applicazione .Net. Si può utilizzare un cursore di riferimento normale in .net ma non un cursore di riferimento che era il cursore dbms_sql.

Quindi quale tipo di client utilizzerà questo cursore?

+0

Sarà usato nel PL/SQL successivo, quindi nessun problema con i client. – Kosi2801

4

È inoltre possibile aggirare il problema utilizzando un'istruzione WITH. Generalmente utilizzando 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; 
+0

Questa è la mia risposta preferita. Lo chiamerei, ad es. 'con vars as (seleziona: 1 v_surname,: 2 v_forename da dual) seleziona person_id da persone dove cognome = (seleziona v_surname da vars) e forename = (seleziona v_forename da vars)' – PhilHibbs

1

Più in particolare, ho bisogno di passare un parametro in SQL sconosciuto, ma non so quanto spesso sarà utilizzato lì.

Io in realtà sono imbattuto in questo esattamente lo stesso problema un paio di giorni fa, e un amico ha condiviso con me un modo di fare esattamente questo con EXECUTE IMMEDIATE.

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

Guarda il mio esempio/codice e per conto mio simile filo domanda/risposta:

Problemi correlati