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

Oracle - RETURNING combinato con funzioni aggregate

Prima di tutto, la documentazione e le funzionalità effettive sono un po' fuori sincronia, quindi le "fonti ufficiali" non faranno luce sui dettagli.

Diagramma sintattico per 10 g R2 (https://docs.oracle .com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm ) è sotto

In 11g (https://docs.oracle.com/ cd/E11882_01/appdev.112/e25519/returninginto_clause.htm ) questo è stato diviso in due:static_returning_clause (per inserire, aggiornare, eliminare) e dynamic_returning_clause (per eseguire immediatamente). Siamo interessati a quello per DML.

Quindi per 10 g c'era una singola espressione di riga che secondo la documentazione è Espressione che restituisce una singola riga di una tabella . È una domanda sottile se l'istruzione DML deve influenzare una singola riga o se è possibile derivare una singola riga dopo l'esecuzione dell'istruzione (ad esempio, utilizzando funzioni di aggregazione). Presumo che l'idea fosse quella di utilizzare questa sintassi quando l'operazione DML interessa una singola riga (al contrario di bulk collect into ); non utilizza funzioni aggregate che restituiscono una singola riga per le righe interessate.

Quindi le funzioni aggregate nel ritorno alla clausola non sono documentate chiaramente. Inoltre, per 11g può apparire solo il nome di una colonna dopo aver restituito la parola chiave, quindi anche espressioni come abs(column_name) non possono non menzionare aggregate_function(column_name), anche se in realtà funziona.

Quindi, a rigor di termini, questa funzionalità con funzioni aggregate non è documentata, soprattutto per 11g, 12c, 18c e non ci si può fare affidamento.

Invece puoi usare "bulk collect into" (e set operator per ottenere un insieme distinto di elementi)

SQL> create type str_tab as table of varchar2(4000)
  2  /

Type created.

SQL> set serveroutput on
SQL> declare
  2    i int;
  3    a str_tab;
  4  begin
  5    delete from t returning val bulk collect into a;
  6    dbms_output.put_line('cnt all ' || a.count || ' cnt distinct ' || set(a).count);
  7    rollback;
  8  end;
  9  /
cnt all 4 cnt distinct 2

PL/SQL procedure successfully completed.

Prestare attenzione anche al messaggio di errore. Dice chiaramente

Non solo "non è consentito distinguere" come in questo esempio

SQL> select listagg(distinct val) within group (order by val) str from t;
select listagg(distinct val) within group (order by val) str from t
       *
ERROR at line 1:
ORA-30482: DISTINCT option not allowed for this function