当前位置: 首页 > 面试题库 >

带排序的递归子查询

裘丰
2023-03-14
问题内容

我在此处查看了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
  • 如果尝试在UNION ALL语句上方添加ORDER BY语句,则会得到某种无效的SQL语法。
  • 您如何解决此问题,以便最后按层次结构中每个深度级别的名称按字母顺序对数据进行排序?

  • (如果数据在连接点正确排序,则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

我的目标:

  • 所有1级按JOBMST_NAME的字母顺序排序
  • 1级中的所有2级按父级按JOBMST_NAME的字母顺序排序
  • 每个父级中,第2级中的所有3级都按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 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的尴尬方言是:

  1. 为什么没有IF表存在删除表?
  2. 为什么必须对字符串执行EXECUTE IMMEDIATE?为什么我不能仅自己做DROP TABLE TEMP?
  3. 为什么没有嵌套在ANCHOR上的括号内就不能拥有ORDER BY?
  4. 为什么在UNION ALL之后不能对递归SELECT进行ORDER BY?
  5. SQL WITH需要标准化。其他数据库方言不需要在WITH语句上用括号括起来的列名。如果不这样做,则会在UNION ALL之后的递归联接时出现一些毫无意义的ALIAS错误。
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


 类似资料:
  • 我正在尝试使用递归编写快速排序代码,但我得到一个堆栈溢出错误。第二个递归函数给出了连续误差。我只是想不通。

  • 我一直在寻找一个递归选择排序,只使用2个参数: 必须排序的数组 一个值k,它指示要对哪个元素进行排序。 示例:a为{6,3,5,7,2}且k为2的SelectionSort(array[]a,int k)将对前3个元素进行排序,并保持最后的元素不变。 我想从一个if语句开始,k为0,如果是这样的话,它就会按原样返回数组,因为您不能对大小为1的数组进行排序。类似于: 我不知道如何做'else'部分,

  • 本文向大家介绍C#递归算法之归并排序,包括了C#递归算法之归并排序的使用技巧和注意事项,需要的朋友参考一下 归并排序是利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列,归并排序包括两个步骤,分别为: 1)划分子表 2)合并半子表 首先我们来讨论归并算法,归并算法将一系列数据放到一个向量中,索引范围为[first,

  • 我正在尝试编写一个ruby方法,它可以递归地执行合并排序。我有这个方法,但这是一次我偶然得到它的工作,所以我不知道它为什么工作,并很想了解我写的代码是如何工作的。在psuedocode中,我遵循的步骤如下所示。 拆分长度为n的原始数组,直到我拥有长度为1的n个数组 一次合并和排序长度为m的2个数组,以返回长度为m*2的数组 重复上述步骤,直到我有一个长度为n的当前排序数组 基本上,在我看来,这是一

  • 表T表示树。每个记录都是一个节点,每个节点只有一个父节点。 该查询计算每个节点的每个分支的SUM()。 我一直在尝试使用替代的子查询分解语法来实现这个查询的相同结果。任何帮助都将不胜感激!

  • 本文向大家介绍Oracle 11GR2的递归WITH子查询方法,包括了Oracle 11GR2的递归WITH子查询方法的使用技巧和注意事项,需要的朋友参考一下 下面给大家详细介绍Oracle 11GR2的递归WITH子查询方法,具体内容如下所示:   L   NM ----  ---------------   1   **KING   2   ****BLAKE   3   ******ALLE