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 l_min:10 l_str: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:此处不允许使用分组功能
问题是为什么不允许使用带有DISTINCT
的聚合函数?
我正在寻找官方消息的答案。
编辑:
请注意,COUNT(DISTINCT ...)
仅是示例。 SUM(col)/SUM(DISTINCT col)
和支持DISTINCT
关键字的任何聚合函数的行为相同。
答案 0 :(得分:3)
首先,文档和实际功能有点不同步,因此“官方资源”将不会透露细节。
10g R2(https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm)的语法图如下
在11g(https://docs.oracle.com/cd/E11882_01/appdev.112/e25519/returninginto_clause.htm)中,这分为两个部分:static_returning_clause(用于插入,更新,删除)和dynamic_returning_clause(用于立即执行)。我们对DML感兴趣。
因此对于10g,有一个单行表达式,根据文档,该表达式为返回表中单行的表达式。执行该语句后可以得出DML语句必须影响单行还是单行这是一个微妙的问题(例如,使用聚合函数)。我假设该想法是在DML操作影响单行时使用此语法(与bulk collect into
相对);不使用会返回受影响行的单行的聚合函数。
因此,不清楚返回in子句中的聚合函数。而且,对于11g,仅在返回关键字后可能会出现一个列名,因此即使实际上像abs(column_name)之类的表达式也不能不提及gregation_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
答案 1 :(得分:0)
主要原因是SQL是不可组合的。 C. J. Date至少在我在北德克萨斯州参加的2009届课堂上表明,SQL是不可组合的。因为它是不可组合的,所以某些东西不是免费的。所谓免费,是指我什至没有思想。但是Server Technologies的人员非常聪明,我相信管理“添加返回功能”项目的人员有意识地确定了分界线。他们显然决定不“完全”编写解析器。我怀疑这是因为他们知道,如果他们采取100%可支持性的立场,那么一旦SQL的其他部分得到增强,那么他们也必须花时间来增强语言的其他部分。
我非常欣赏ST的SQL解析器执行速度以及它产生错误结果的罕见程度。但是我想知道,但占主导地位的查询语言至少是可组合的,世界会比现在更好吗?