Oracle
 sql >> Database >  >> RDS >> Oracle

È possibile utilizzare GROUP BY con variabili bind?

Suggerisco di riscrivere l'istruzione in modo che ci sia un solo argomento di binding. Questo approccio è un po' brutto, ma restituisce il set di risultati:

select max(col1) 
     , f_col2
  from (
         select col1
              , f(? ,col2) as f_col2 
           from t
       )
 group
    by f_col2

Questa istruzione riscritta ha un riferimento a un solo argomento di collegamento, quindi ora il DBMS vede le espressioni nella clausola GROUP BY e l'elenco SELECT sono identiche.

HTH

[MODIFICA]

(Vorrei che ci fosse un modo più carino, ecco perché preferisco l'approccio dell'argomento bind denominato utilizzato da Oracle. Con il driver Perl DBI, gli argomenti posizionali vengono convertiti in argomenti denominati nell'istruzione effettivamente inviata a Oracle.)

All'inizio non ho visto il problema, non ho capito la domanda originale. (Apparentemente, anche molte altre persone lo hanno perso.) Ma dopo aver eseguito alcuni casi di test, mi sono reso conto di quale fosse il problema, quale fosse la domanda.

Vediamo se posso esporre il problema:come ottenere due argomenti bind (posizionali) separati da trattare (dal DBMS) come se fossero due riferimenti allo stesso argomento bind (con nome).

Il DBMS si aspetta che l'espressione in GROUP BY corrisponda all'espressione nell'elenco SELECT. Ma le due espressioni sono considerate DIVERSE anche quando le espressioni sono identiche, quando l'unica differenza è che ciascuna espressione fa riferimento a una diversa variabile di binding. (Possiamo dimostrare alcuni casi di test che almeno alcuni DBMS consentiranno, ma ci sono casi più generali che solleveranno un'eccezione.)

A questo punto la risposta breve è che mi ha perplesso. Il suggerimento che ho (che potrebbe non essere una risposta effettiva alla domanda originale) è di ristrutturare la query.

[/MODIFICA]

Posso fornire maggiori dettagli se questo approccio non funziona o se hai qualche altro problema a capirlo. O se c'è un problema con le prestazioni (posso vedere l'ottimizzatore che sceglie un piano diverso per la query riscritta, anche se restituisce il set di risultati specificato. Per ulteriori test, avremmo davvero bisogno di sapere quale DBMS, quale driver, statistiche, ecc.)

MODIFICA (otto anni e mezzo dopo)

Un altro tentativo di riscrittura di una query. Ancora una volta, l'unica soluzione che mi viene in mente è una query con un segnaposto di associazione. Questa volta, lo inseriamo in una vista in linea che restituisce una singola riga e la uniamo a t. Posso vedere cosa sta facendo; Non sono sicuro di come lo vedrà l'ottimizzatore Oracle. Potremmo voler (o aver bisogno) di eseguire una conversione esplicita, ad es. TO_NUMBER(?) AS param , TO_DATE(?,'...') AS param , TO_CHAR(?) AS param , a seconda del tipo di dati del parametro bind e del tipo di dati che vogliamo che venga restituito dalla vista.)

Ecco come lo farei in MySQL. La query originale nella mia risposta esegue l'operazione di unione all'interno della vista inline (MySQL tabella derivata ). E vogliamo evitare di materializzare una tabella derivata da hughjass se possiamo evitarlo. Inoltre, MySQL probabilmente lascerebbe scorrere la query originale finché sql_mode non include ONLY_FULL_GROUP_BY . MySQL ci permetterebbe anche di eliminare il FROM DUAL )

  SELECT MAX(t.col1)
       , f( v.param ,t.col2)
    FROM t
   CROSS
    JOIN ( SELECT ? AS param FROM DUAL) v
   GROUP
      BY f( v.param ,t.col2)

Secondo la risposta di MadusankaD, negli ultimi otto anni Oracle ha aggiunto il supporto per riutilizzare gli stessi parametri di binding denominati nel driver JDBC e mantenere l'equivalenza. (Non l'ho testato, ma se funziona ora, allora fantastico.)