我刚刚遇到了这个interesting article here,展示了如何使用分层查询和窗口函数在Oracle中模拟wm_concat()
或group_concat()
:
SELECT deptno,
LTRIM(MAX(SYS_CONNECT_BY_PATH(ename,','))
KEEP (DENSE_RANK LAST ORDER BY curr),',') AS employees
FROM (SELECT deptno,
ename,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) AS curr,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS prev
FROM emp)
GROUP BY deptno
CONNECT BY prev = PRIOR curr AND deptno = PRIOR deptno
START WITH curr = 1;
虽然,我发现这不是一个非常易读的解决方案,但它非常有趣,特别是因为CONNECT BY .. STARTS WITH
子句在 GROUP BY
子句后出现。根据{{3}},这是不可能的。我尝试使用一个简单的查询,但它确实有效!以下两个查询返回相同的结果:
-- wrong according to the specification:
select level from dual group by level connect by level <= 2;
-- correct according to the specification:
select level from dual connect by level <= 2 group by level;
这是一个无证件的功能吗?或者只是方便的语法冷漠?或者这两个陈述巧妙地表现得不同?
答案 0 :(得分:2)
查看执行计划。在我的环境中,它们是相同的,CONNECT BY操作输入HASH GROUP BY。所以看起来首先放置GROUP BY只是一种奇怪的语法,它产生的结果与更自然的顺序相同。
从技术上讲,这可能是解析器中的一个错误,因为正如您所说,规范表明层次查询子句应该在group-by子句之前。但它似乎没有对查询的执行方式产生任何影响。
答案 1 :(得分:2)
我认为这只是一个无关紧要的语法差异。
更具体地说,我认为这是一个文档错误。 8i的语法图表示支持任一顺序。 8i reference中没有任何内容暗示订单有任何区别。但该图表也暗示您可以拥有多个group_by_clause
或hierarchical_query
,这不是真的:
--You can't group twice: ORA-01787: only one clause allowed per query block
select level from dual connect by level <= 2 group by level group by level;
我的猜测是,当Oracle修复了9i的语法图时,他们也忘了订单可能会有所不同。或者他们可能故意将其排除在外,因为首先执行分层部分似乎更合乎逻辑。
这样的一些次要语法变体没有记录。我认为这并不意味着它们不受支持。 Oracle可能会后悔允许这么多奇怪的选项,并希望事情至少看起来很简单。例如,HAVING
可以在GROUP BY
之前出现,许多旧的并行功能仍然有效(但被忽略)等等。(这就是为什么当人们说他们要快速“解析”时,我总是笑SQL“ - 祝你好运!”
Oracle 8i语法:
Oracle 9i语法: