9

我刚刚在这里看到了这篇有趣的文章,展示了如何在 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子句之后。根据规范,这应该是不可能的。我已经使用一个简单的查询进行了尝试,但它确实有效!以下两个查询返回相同的结果:

-- 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;

这是一个未记录的功能吗?或者只是为了方便起见语法冷漠?或者这两种说法是否有微妙的不同?

4

2 回答 2

4

我认为这只是一个微不足道的语法差异。

更具体地说,我认为这是一个文档错误。8i 的语法图暗示支持任一顺序。8i 参考中的任何内容都没有暗示顺序有任何区别。但是该图也暗示您可以有多个group_by_clauseor 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 的语法图时,他们也忘记了顺序可能不同。或者他们可能故意忽略它,因为首先做分层部分似乎更合乎逻辑。

有几个像这样的小语法变化是未记录的。我不认为这意味着它们不受支持。甲骨文可能后悔允许这么多奇怪的选择,并希望事情至少看起来简单。例如,HAVINGcan come before GROUP BY,许多旧的并行功能仍然有效(但被忽略)等等。(这就是为什么当人们说他们要快速“解析 SQL”时我总是笑——祝你好运!)

Oracle 8i 语法: Oracle 8i SELECT 语法

Oracle 9i 语法: Oracle 9i SELECT 语法

于 2012-04-07T16:05:50.110 回答
3

查看执行计划。在我的环境中,它们是相同的,将 CONNECT BY 操作输入 HASH GROUP BY。因此,将 GROUP BY 放在首位似乎只是一种奇怪的语法,它产生的结果与更自然的排序相同。

从技术上讲,这可能是解析器中的一个错误,因为正如您所说,规范表明分层查询子句应该在 group-by 子句之前。但它似乎对查询的执行方式没有任何影响。

于 2012-04-06T13:12:35.520 回答