Oracle supports RETURNING
clause which could be very useful.
For example for data:
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;
Query:
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
It supports 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 l_min:10 l_str:10,20,30,40
Unfortunately when combined with DISTINCT
keyword I get an error:
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: group function is not allowed here
The question is why aggregate functions with DISTINCT
are not allowed?
I am looking for an answer drawing from official sources.
EDIT:
Please note that COUNT(DISTINCT ...)
was only an example. Same behavior is for SUM(col)/SUM(DISTINCT col)
and any aggregate function that supports DISTINCT
keyword.
COUNT(val)
is working fine, butCOUNT(DISTINCT val)
is treated differently db<>fiddle demo – Chrysostomreturning count(*)
acts likesql%rowcount
. – BeatifyMIN/MAX/LISTAGG
. AnywaySUM(id)
will work butSUM(DISTINCT id)
won't work. So the root of the problem isDISTINCT
. – Chrysostomcount(distinct ...)
is T = O (n log n ) whereas the rest of the potential aggregation functions is T = O (n ). In other words, you are forbidden to ask for an additional sort of the data being returned from your query. In another words, the PL/SQL engine does not want to store the query results anywhere in memory, it only wants to loop through them in a pipelined fashion and calculate your aggregate. However, I also don't know of any official sources for this specific behaviour. – Romanticismsubquery
will allow to run arbitrary aggregate but unfortunately the data is taken from snapshot just before operationDELETE
. – Chrysostom