我在此处查看了Tim Hall的精彩文章,该文章允许您使用自引用实体并使用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
您如何解决此问题,以便最后按层次结构中每个深度级别的名称按字母顺序对数据进行排序?
(如果数据在连接点正确排序,则SEARCH DEPTH FIRST创建的DISP_SEQ应该正确整理数据)。
您最终得到的是这样的东西(名称被省略):
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
我的目标:
更新:我设法对代码进行了一些调整,因此对锚选择进行了排序:
但是我似乎无法将相同的语法糖应用于递归联接。
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
最初,我看不到比创建临时表更好的解决方案。
我当时在想,SQL Oracle的尴尬方言是:
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;
然后(Oracle社区论坛上的mathguy)向我指出,我的SEARCH DEPTH FIRST应该只是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