带排序的递归子查询

Recursive Subquerying with sorting

我看了 Tim Hall 的优秀文章 here,它允许您使用自引用实体并显示分层数据(从顶级节点开始并递归地返回),在 Oracle 中使用类似 CTE 的语法.

所以我的代码看起来像这样:

WITH J1(JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, LVL) AS  (   
  SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, 1   
  FROM TIDAL.JOBMST   
  WHERE JOBMST_PRNTID IS NULL   
  UNION ALL   
  SELECT J2.JOBMST_ID,J2.JOBMST_NAME,J2.JOBMST_PRNTID, J2.JOBMST_TYPE, J1.LVL+1    
  FROM TIDAL.JOBMST J2    
  INNER JOIN J1 ON J2.JOBMST_PRNTID = J1.JOBMST_ID    
  WHERE J2.JOBMST_PRNTID IS NOT NULL)    
SEARCH DEPTH FIRST BY JOBMST_ID SET DISP_SEQ
SELECT *
FROM J1
ORDER BY DISP_SEQ

对于锚行(我的 SQL 中的顶级层次结构 J1 条目,父级为 NULL),我想:

 ORDER BY  J1.JOBMST_NAME 

对于递归连接:

ORDER BY J2.JOBMST_PRNTID, J2.JOBMST_NAME

你最终得到这样的东西(省略名字):

JOBMST_ID JOBMST_NAME JOBMST_PRNTID JOBMST_TYPE LVL DISP_SEQ
 746                                1           1   1
1433                                1           1   2
1328                   1433         1           2   3
1329                   1328         1           3   4
1330                   1329         1           4   5
1331                   1329         1           4   6
1332                   1329         1           4   7

我的目标:


更新: 我设法稍微调整了代码,所以锚 select 被排序:

但我似乎无法将相同的语法糖应用于递归连接。

WITH J1(JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, LVL) AS  (
  SELECT * FROM (
    SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, 1
    FROM TIDAL.JOBMST
    WHERE JOBMST_PRNTID IS NULL
    ORDER BY JOBMST_NAME
  )
UNION ALL
SELECT J2.JOBMST_ID, J2.JOBMST_NAME, J2.JOBMST_PRNTID, J2.JOBMST_TYPE, J1.LVL + 1
FROM TIDAL.JOBMST J2
INNER JOIN J1 ON J2.JOBMST_PRNTID = J1.JOBMST_ID
WHERE J2.JOBMST_PRNTID IS NOT NULL
)
SEARCH DEPTH FIRST BY JOBMST_ID SET DISP_SEQ
SELECT *
FROM J1
ORDER BY DISP_SEQ

最初,我找不到比创建临时文件更优雅的解决方案 table。

我在想,SQL Oracle 的方言是多么尴尬:

  1. 为什么没有 IF TABLE EXISTS DELETE TABLE?
  2. 为什么我必须对字符串执行 EXECUTE IMMEDIATE?为什么我不能单独执行 DROP TABLE TEMP?
  3. 为什么我不能在不嵌套在 ANCHOR 括号中的情况下使用 ORDER BY?
  4. 为什么我不能在 UNION ALL 之后对递归 SELECT 使用 ORDER BY?
  5. SQL WITH 需要标准化。其他数据库方言不需要在 WITH 语句中用括号括起列名。如果你不这样做,你会得到一些无意义的 ALIAS 错误,在 UNION ALL 之后的递归连接点。
  6. 分页:参见here无限制/偏移

DECLARE
 v_c NUMBER;
BEGIN
SELECT COUNT(*) INTO v_c FROM user_tables WHERE TABLE_NAME = 'TEMP';
IF v_c = 1 THEN
  EXECUTE IMMEDIATE 'DROP TABLE TEMP';
END IF;
END;
CREATE TABLE TEMP AS  (
    SELECT * FROM (
      SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE
      FROM TIDAL.JOBMST
      WHERE JOBMST_PRNTID IS NOT NULL
      ORDER BY JOBMST_PRNTID, JOBMST_NAME
    )
);
WITH J1(JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, LVL) AS  (
  SELECT * FROM (
    SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, 1
    FROM TIDAL.JOBMST
    WHERE JOBMST_PRNTID IS NULL
    ORDER BY JOBMST_NAME
  )
UNION ALL
SELECT J2.JOBMST_ID, J2.JOBMST_NAME, J2.JOBMST_PRNTID, J2.JOBMST_TYPE, J1.LVL + 1
FROM TEMP J2
INNER JOIN J1 ON J2.JOBMST_PRNTID = J1.JOBMST_ID
WHERE J2.JOBMST_PRNTID IS NOT NULL
)
SEARCH DEPTH FIRST BY JOBMST_ID SET DISP_SEQ
SELECT *
FROM J1
ORDER BY DISP_SEQ;

然后 (mathguy on the Oracle Community Forum) 向我指出我的搜索深度优先应该在 JOBMST_NAME 之前完成。

然后一切就绪:

WITH J1(JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, LVL) AS  (
    SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, 1
    FROM TIDAL.JOBMST
    WHERE JOBMST_PRNTID IS NULL
UNION ALL
SELECT J2.JOBMST_ID, J2.JOBMST_NAME, J2.JOBMST_PRNTID, J2.JOBMST_TYPE, J1.LVL + 1
FROM TIDAL.JOBMST J2
INNER JOIN J1 ON J2.JOBMST_PRNTID = J1.JOBMST_ID
WHERE J2.JOBMST_PRNTID IS NOT NULL
)
SEARCH DEPTH FIRST BY JOBMST_NAME SET DISP_SEQ
SELECT *
FROM J1
ORDER BY DISP_SEQ