Oracle - ВОЗВРАТ в сочетании с агрегатными функциями - PullRequest
0 голосов
/ 14 сентября 2018

Oracle поддерживает предложение RETURNING, которое может быть очень полезным.

Например, для данных:

CREATE TABLE t(Id INT, Val varchar2(50));

INSERT INTO t(Id, Val)
SELECT 10,'a' FROM dual
UNION ALL SELECT 20,'b' FROM dual
UNION ALL SELECT 30,'a' FROM dual
UNION ALL SELECT 40,'b' FROM dual;

Запрос:

DECLARE
   l_cnt INT;
BEGIN
   DELETE FROM t RETURNING COUNT(*) INTO l_cnt;
   DBMS_OUTPUT.put_line('l_cnt: ' || l_cnt);
END;

l_cnt: 4

Поддерживает MIN / MAX / AVG / SUM / LISTAGG:

DECLARE
   l_max INT;
   l_min INT;
   l_str VARCHAR2(100);
BEGIN
   DELETE FROM t 
   RETURNING MAX(id), MIN(id), LISTAGG(id, ',') WITHIN GROUP(ORDER BY id) 
   INTO l_max, l_min, l_str;
   DBMS_OUTPUT.put_line('l_max:'||l_max||' l_min:'||l_min||' l_str:'|| l_str);
END;

l_max: 40 л_мин: 10 л_стр: 10,20,30,40

К сожалению, в сочетании с ключевым словом DISTINCT появляется ошибка:

DECLARE
   l_distinct_cnt INT;
BEGIN
   DELETE FROM t 
   RETURNING COUNT(DISTINCT val) INTO l_distinct_cnt ;
   DBMS_OUTPUT.put_line('l_distinct_cnt:' || l_distinct_cnt );
END;

ORA-00934: групповая функция здесь не разрешена

db <> демо fiddle

Вопрос в том, почему агрегатные функции с DISTINCT не разрешены? Я ищу ответный чертеж из официальных источников.


EDIT:

Обратите внимание, что COUNT(DISTINCT ...) был только примером. То же самое относится к SUM(col)/SUM(DISTINCT col) и любой статистической функции, которая поддерживает ключевое слово DISTINCT.

СУММА (val) против SUM (DISTINCT val)

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Прежде всего, документация и фактическая функциональность немного не синхронизированы, поэтому «официальные источники» не проливают свет на детали.

Синтаксическая схема для 10g R2 (https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm) ниже enter image description here

В 11g (https://docs.oracle.com/cd/E11882_01/appdev.112/e25519/returninginto_clause.htm) это было разделено на два: static_returning_clause (для вставки, обновления, удаления) и dynamic_returning_clause (для немедленного выполнения). Нас интересует один для DML. enter image description here

Таким образом, для 10g существовало единственное выражение строки, которое согласно документации Выражение, которое возвращает одну строку таблицы . Сложно задать вопрос, должен ли оператор DML влиять на одну строку, или же одна строка может быть получена после выполнения оператора (скажем, с помощью агрегатных функций). Я предполагаю, что идея состояла в том, чтобы использовать этот синтаксис, когда операция DML влияет на одну строку (в отличие от bulk collect into); не использует агрегатные функции, которые возвращают одну строку для затронутых строк.

Таким образом, агрегатные функции при возвращении в предложение четко не документированы. Более того, для 11g после возврата ключевого слова может появиться только имя столбца, поэтому даже выражение вроде abs (column_name) не может не упоминать aggregate_function (column_name), хотя в действительности это работает.

Итак, строго говоря, эта функциональность с агрегатными функциями не документирована, особенно для 11g, 12c, 18c, и вы не можете на нее полагаться.

Вместо этого вы можете использовать «массовый сбор в» (и оператор set для получения различного набора элементов)

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.

Обратите также внимание на сообщение об ошибке. Это ясно говорит

ORA-00934: группа функция здесь не разрешена

Не просто "не разрешено отличное", как в этом примере

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
0 голосов
/ 17 сентября 2018

Основная причина в том, что SQL не может быть компонован. К. Дж. Дэйт показал, по крайней мере, в классе 2009 года, который я посещал в Северном Техасе, что SQL не поддается компоновке. Потому что это не сочетаемо, некоторые вещи не приходят бесплатно. И под свободой я имею в виду, даже не задумываясь. Но люди в Server Technologies довольно умны, и я уверен, что те, кто управлял проектом «добавить возвращение», сознательно решили, где провести черту. Очевидно, они решили, что не будут «полностью» писать парсер. Я подозреваю, что это потому, что они знали, что если они займут позицию 100% -ной поддержки, то, как только будет улучшена какая-то другая часть SQL, им придется также потратить время на усовершенствование других частей языка.

Я восхищаюсь ST за то, как быстро работает их анализатор SQL и как редко он дает неверные результаты. Но мне интересно, но не так страстно, как мистер Дэйт, насколько лучше мог бы быть мир, если бы доминирующий язык запросов был хотя бы составным.

...