Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle - RETURNING kombiniert mit Aggregatfunktionen

Zunächst einmal stimmen Dokumentation und eigentliche Funktionalität etwas nicht überein, sodass "offizielle Quellen" kein Licht auf die Details werfen werden.

Syntaxdiagramm für 10g R2 (https://docs.oracle .com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm ) finden Sie unter

In 11g (https://docs.oracle.com/ cd/E11882_01/appdev.112/e25519/returninginto_clause.htm ) wurde dies in zwei Teile aufgeteilt:static_returning_clause (für Insert, Update, Delete) und dynamic_returning_clause (für Execute Instant). Uns interessiert die für DML.

Für 10g gab es also einen einzelnen Zeilenausdruck, der laut Dokumentation Ausdruck, der eine einzelne Zeile einer Tabelle zurückgibt ist . Es ist eine subtile Frage, ob eine DML-Anweisung eine einzelne Zeile betreffen muss oder ob eine einzelne Zeile nach der Ausführung der Anweisung abgeleitet werden kann (z. B. durch Verwendung von Aggregatfunktionen). Ich nehme an, die Idee war, diese Syntax zu verwenden, wenn die DML-Operation eine einzelne Zeile betrifft (im Gegensatz zu bulk collect into). ); keine Aggregatfunktionen verwenden, die einzelne Zeilen für betroffene Zeilen zurückgeben.

Daher sind Aggregatfunktionen beim Zurückkehren in die Klausel nicht eindeutig dokumentiert. Darüber hinaus kann für 11g nur ein Spaltenname nach der Rückgabe des Schlüsselworts erscheinen, so dass selbst Ausdrücke wie abs(column_name) nicht zulässig sind, ohne Aggregate_function(column_name) zu erwähnen, obwohl es in Wirklichkeit funktioniert.

Genau genommen ist diese Funktionalität mit Aggregatfunktionen also nicht dokumentiert, insbesondere für 11g, 12c, 18c, und Sie können sich darauf nicht verlassen.

Stattdessen können Sie "Bulk Collect into" verwenden (und den Set-Operator verwenden, um einen bestimmten Satz der Elemente zu erhalten)

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.

Achten Sie auch auf die Fehlermeldung. Da steht ganz klar

Nicht nur "eindeutig ist nicht erlaubt" wie in diesem Beispiel

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