简体   繁体   English

具有2个表的递归CTE在Oracle / SQL中不起作用

[英]Recursive CTE with 2 tables not working in Oracle / SQL

There are 2 tables Department and subdepartment which have id in common. 有2个表Departmentsubdepartment Department具有共同的ID。 I am trying to recursively fetch all the ids reporting to AB directly and indirectly. 我试图递归地获取直接和间接向AB报告的所有ID。 BC is reporting to AB, hence 4,5,6 are indirectly reporting to AB, likewise fetching till the last id. BC向AB报告,因此4,5,6间接向AB报告,同样获取直到最后一个ID。

Tried the below recursive CTE query but I am getting the result of only the first level. 尝试了下面的递归CTE查询,但是我只得到第一级的结果。 Seems recursive query is not executing. 似乎recursive查询未执行。

I am not sure what is wrong in the query. 我不确定查询中出了什么问题。 Can someone help me in spotting the error. 有人可以帮助我发现错误。

Department

Name     id
AB          1
AB          2
AB          3
BC          4
BC          5
BC          6
CD          7
CD          8
EF          9
EF         10
EF         11

Subdepartment SUBDEPARTMENT

ID      Reporting
1
2
3         BC
4
5         CD
6
7
8         EF
9
10
11

Query: 查询:

With reportinghierarchy (Name, Id, Reporting, Level) As
(

--Anchor
Select A.name,A.id,reporting,0 from department A, subdepartment B
where A.id=B.id and A.name='AB'

Union All

--Recursive member
Select C.name,C.id,D.reporting, Level+1 from department C, subdepartment D
Inner Join  reportinghierarchy R
On (C.Name = R.reporting)
Where C.name != 'AB' and C.Id =D.id
And R.Reporting is not null
)
Select * from reportinghierarchy

Current Output : 电流输出

Name Id  Reporting  Level
AB   1                0
AB   2                0
AB   3   BC           0

Expected output : 预期产量:

Name     id     Reporting  Level
AB        1                  0
AB        2                  0
AB        3       BC         0
BC        4                  1
BC        5       CD         1
BC        6                  1
CD        7                  2
CD        8       EF         2
EF        9                  3
EF       10                  3
EF       11                  3

Hmmm, "horrible data structure" comes to mind. 嗯,“可怕的数据结构”浮现在脑海。 This approach gets one row per "reporting" name to use for the recursive CTE portion. 此方法为每个“报告”名称获取一行以用于递归CTE部分。 It then joins the level back to the original data. 然后,它将级别返回到原始数据。

with ds as (
      select d.name, d.id, sd.reporting
      from department d join
           subdepartment sd
           on d.id = sd.id
     ),
     nd as (
      select d.name, sd.reporting
      from ds
      where sd.reporting is not null
     ),
     cte as (
      select ds.name, nd.reporting, 0 as lev
      from nd
      where not exists (select 1 from nd nd2 where nd2.reporting = nd.name)
      union all
      select nd.name, nd.reporting, lev + 1
      from cte join
           nd
           on nd.name = cte.reporting 
    )
select ds.*, cte.lev
from ds join
     cte
     on ds.name = cte.name;

Also, learn to use proper, explicit JOIN syntax. 另外,学习使用正确的显式JOIN语法。 It has been the standard syntax for decades. 数十年来,它一直是标准语法。

Your original query was actually VERY, VERY close to working. 您原来的查询实际上非常非常接近。 The reasons it didn't work are: 它不起作用的原因是:

  1. You used the keyword LEVEL as a column name without quoting it. 您使用关键字LEVEL作为列名而不引用它。 In Oracle LEVEL has specific meaning, and using it out of context causes the parser no end of headaches. 在Oracle中, LEVEL具有特定的含义,在上下文之外使用它会使解析器无休止地头痛。 I've changed it to LVL , which works fine. 我将其更改为LVL ,它可以正常工作。
  2. In the recursive half of the UNION you mixed old-style and new-style joins . 在UNION的递归部分中, 您混合了旧式和新式联接 This is a huge problem and should never be done. 这是一个巨大的问题,绝不应该做。 Either use "old-style" implied joins, or use "new-style" explicit joins. 使用“旧式”隐式连接,或使用“新式”显式连接。 To keep as close to your original as possible I used implicit joins, but good coding practice says you should use explicit joins all the time. 为了尽可能地接近您的原始语言,我使用了隐式连接,但是良好的编码实践表明您应该一直使用显式连接。

The corrected query is: 更正后的查询是:

With reportinghierarchy (Name, Id, Reporting, lvl) As
(

--Anchor
Select A.name,A.id,reporting,0 from department A, subdepartment B
where A.id=B.id and A.name='AB'

Union All

--Recursive member
Select C.name,C.id,D.reporting, lvl+1 from department C, subdepartment D, reportinghierarchy R
Where C.name != 'AB' and C.Id =D.id and C.Name = R.reporting
And R.Reporting is not null
)
Select * from reportinghierarchy;

Given the above, the following results are returned, which appear to match your desired results: 鉴于以上所述,将返回以下结果,这些结果似乎与您期望的结果相匹配:

NAME    ID  REPORTING   LVL
AB      1   (null)      0
AB      2   (null)      0
AB      3   BC          0
BC      4   (null)      1
BC      5   CD          1
BC      6   (null)      1
CD      7   (null)      2
CD      8   EF          2
EF      9   (null)      3
EF      10  (null)      3
EF      11  (null)      3

SQLFiddle here SQLFiddle在这里

Best of luck. 祝你好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM