【问题标题】:Oracle/SQL: Recursive Query for a Many-to-many relationshipOracle/SQL:多对多关系的递归查询
【发布时间】:2021-09-19 05:13:45
【问题描述】:

我正在尝试在 Oracle SQL 中进行查询,该查询能够通过其父项找到所有连接的记录,然后找到子项的父项,依此类推。

我一直在研究 CONNECT BY 和 START WITH 选择查询,但我找不到适合我正在尝试做的示例。

为了提高执行速度,我宁愿只使用 SQL 和/或避免使用循环。

例如:

表:

Row# ID-A ID-B
1 ABC 123
2 BCA 123
3 CBA 123
4 CBA 321
5 CAB 321
6 BAC 213

搜索:“BCA” 预期记录:第 1、2、3、4 和 5 行

*旁注:ID-B 是另一个以 ID-B 作为主键的表的外键。

如果我搜索“BCA”,它将找到具有相同 ID-B (123) 的所有其他记录。所以它找到第 1 行和第 2 行,但是当它找到第 3 行的记录时 |联邦银行 | 123 |它会查找 ID-A 为“CBA”的任何其他记录。然后正因为如此,它也会查找 ID-B 为“321”的所有记录,依此类推。

我不确定我是否解释得足够好,所以请让我知道任何不清楚的地方。

只是一些测试代码,但这是我尝试过的一些:

    WITH TEST_1 (IDProd, IDRelation, Generation) AS
    (
      
      SELECT bu.bu_num
      , TO_CHAR(bu.bu_num)
      , 0
      FROM BU_TAB bu
     WHERE bu.bu_num = 12345

      UNION ALL
      
      
      SELECT T.IDPROD
      , CASE WHEN t.Generation <= 0 THEN TO_CHAR(d.bu_num)
        ELSE TO_CHAR(d.da_identifier) END
       , CASE WHEN t.Generation <= 0 THEN T.Generation - 1
        ELSE T.Generation + 1  END
      FROM TEST_1 T
      inner join DA_TAB d
      on d.bu_num = T.IDRelation
      where t.Generation <= 0
      

    )
    SELECT * 
    FROM TEST_1
    order by IDProd, Generation



  SELECT level, d.da_identifier, bu.bu_num
    FROM BU bu
       , DA_TAB d
   WHERE bu.bu_num = d.bunit_num
   START WITH bu.bu_num = 12345
   CONNECT BY PRIOR bu.bu_num = b.bu_num

【问题讨论】:

  • 到目前为止你尝试了什么?
  • 发布您尝试过的实际 SQL 会有所帮助。
  • 我尝试使用此示例 sqlfiddle.com/#!18/319431/4 以及使用 CONNECT BY 和 START WITH 的查询
  • 您的小提琴在 SQL 服务器上,您的标签说是 oracle。我假设是 oracle,因为您之前提到过连接...
  • 我会发布我的代码,我只需要快速清理它

标签: sql oracle recursion plsqldeveloper


【解决方案1】:

我想我能弄明白;当然,结果并不是那么令人印象深刻,而且它比我研究几个小时时想象的要简单得多。我仍然需要完全验证结果并确保一切都符合我的预期,但就像 mathguy 在 cmets 中所说的那样:我能够通过连接来做到这一点,而且我的数据似乎很快,但就我而言'已经看到它只需要扩展到大约 8 级的路径。

如果有人好奇,这里就是它的核心:

 SELECT DISTINCT b1.da_identifier AS daid2
               /*, b.da_identifier
               , b.bu_num
               , b1.bu_num AS bu_num2
               , CONNECT_BY_ROOT b.da_identifier
               , SYS_CONNECT_BY_PATH (b.da_identifier, '|')
               , LEVEL AS lvl*/
   FROM DA_TAB b
   JOIN DA_TAB b1 ON b1.da_identifier = b.da_identifier 
                 AND b1.bu_num <> b.bu_num --Probably not needed
  START WITH b.da_identifier = 'ABCXYZ123'
CONNECT BY NOCYCLE PRIOR b.bu_num = b1.bu_num

我找不到任何关于我的确切情况的例子,所以我想如果有人可以从中受益,我不妨发布它。

【讨论】: