Oracle
 sql >> Base de données >  >> RDS >> Oracle

Oracle - RETURNING combiné avec des fonctions d'agrégation

Tout d'abord, la documentation et les fonctionnalités réelles sont un peu désynchronisées, de sorte que les "sources officielles" ne feront pas la lumière sur les détails.

Diagramme syntaxique pour 10g R2 (https://docs.oracle .com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm ) est ci-dessous

Dans 11g (https://docs.oracle.com/ cd/E11882_01/appdev.112/e25519/returninginto_clause.htm ) cela a été divisé en deux :static_returning_clause (pour insérer, mettre à jour, supprimer) et dynamic_returning_clause (pour exécuter immédiatement). Nous sommes intéressés par celui pour DML.

Donc, pour 10g, il y avait une seule expression de ligne qui, selon la documentation, est Expression qui renvoie une seule ligne d'une table . C'est une question subtile de savoir si l'instruction DML doit affecter une seule ligne ou si une seule ligne peut être dérivée après l'exécution de l'instruction (par exemple, en utilisant des fonctions d'agrégation). Je suppose que l'idée était d'utiliser cette syntaxe lorsque l'opération DML affecte une seule ligne (par opposition à bulk collect into ); ne pas utiliser de fonctions d'agrégation qui renvoient une seule ligne pour les lignes affectées.

Ainsi, les fonctions d'agrégation en retournant dans la clause ne sont pas clairement documentées. De plus, pour 11g, seul un nom de colonne peut apparaître après le retour du mot-clé, donc même une expression comme abs(column_name) n'est pas autorisée à ne pas mentionner l'aggreggate_function(column_name), même si en réalité cela fonctionne.

Donc, à proprement parler, cette fonctionnalité avec des fonctions d'agrégation n'est pas documentée, en particulier pour 11g, 12c, 18c et vous ne pouvez pas vous y fier.

Au lieu de cela, vous pouvez utiliser "collecte en masse dans" (et définir l'opérateur pour obtenir un ensemble distinct d'éléments)

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.

Faites également attention au message d'erreur. Il dit clairement

Pas seulement "distinct n'est pas autorisé" comme dans cet exemple

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