Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Oracle - RETURNING combinado com funções agregadas


Em primeiro lugar, a documentação e a funcionalidade real estão um pouco fora de sincronia, então "fontes oficiais" não esclarecerão os detalhes.

Diagrama sintático para 10g R2 (https://docs.oracle .com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm ) está abaixo

Em 11g (https://docs.oracle.com/ cd/E11882_01/appdev.112/e25519/returninginto_clause.htm ) foi dividido em dois:static_returning_clause (para inserir, atualizar, excluir) e dynamic_returning_clause (para executar imediatamente). Estamos interessados ​​no DML.

Portanto, para 10g havia uma expressão de linha única que, de acordo com a documentação, é Expressão que retorna uma única linha de uma tabela . É uma questão sutil se a instrução DML deve afetar uma única linha ou uma única linha pode ser derivada após a execução da instrução (digamos, usando funções agregadas). Suponho que a ideia era usar essa sintaxe quando a operação DML afeta uma única linha (em oposição a bulk collect into ); não usando funções agregadas que retornam uma única linha para as linhas afetadas.

Portanto, as funções agregadas ao retornar à cláusula não são documentadas claramente. Além disso, para 11g, apenas um nome de coluna pode aparecer após o retorno da palavra-chave, portanto, mesmo expressões como abs(column_name) não podem não mencionar agregado_function(column_name), mesmo que na realidade funcione.

Então, estritamente falando, essa funcionalidade com funções agregadas não está documentada, especialmente para 11g, 12c, 18c e você não pode confiar nela.

Em vez disso, você pode usar "coletar em massa em" (e definir o operador para obter um conjunto distinto de elementos)
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.

Preste também atenção à mensagem de erro. Diz claramente

Não apenas "distinto não é permitido" como neste exemplo
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