使用CONNECT BY PREVIOR进行分层查询-Oracle SQL
我目前正在处理一个需要层次化查询的需求,但我似乎无法正确处理 要求是: 对于给定的一组订单,找出它们的所有需求,以及补充这些需求的内容。然后,如果补货是使用CONNECT BY PREVIOR进行分层查询-Oracle SQL,sql,oracle,recursion,Sql,Oracle,Recursion,我目前正在处理一个需要层次化查询的需求,但我似乎无法正确处理 要求是: 对于给定的一组订单,找出它们的所有需求,以及补充这些需求的内容。然后,如果补货是MAKE类型(即另一个订单),则找出其所有需求和补货等 fiddle末尾的结果查询本质上是这样的:对于订单x,这里是它的所有需求。对于这些需求中的每一项,下面是计划补充的内容 我现在需要做的是,对于所有的制造类型补充,我需要继续重复这个过程,加入这些表,提取补充的内容,等等,但是这样做的同时跟踪顶级订单 我希望将其转换为如下所示的数据集: |
MAKE
类型(即另一个订单),则找出其所有需求和补货等
fiddle末尾的结果查询本质上是这样的:对于订单x,这里是它的所有需求。对于这些需求中的每一项,下面是计划补充的内容
我现在需要做的是,对于所有的制造类型补充,我需要继续重复这个过程,加入这些表,提取补充的内容,等等,但是这样做的同时跟踪顶级订单
我希望将其转换为如下所示的数据集:
| Root Order | Order_Number | Requirement_ID | Replenishment_ID | Replenishment_Type | Replenishment_Detail | Replenishment_Date |
|:----------:|:------------:|:--------------:|:----------------:|:------------------:|:--------------------:|:------------------:|
| 300 | 300 | AA-300 | RO601 | Bought | 963 | 7/15/2018 |
| 300 | 300 | AA-300 | RO111 | Make | 251 | 10/23/2018 |
| 300 | 300 | AA-300 | RO435 | Make | 837 | 3/4/2018 |
| 300 | 300 | AA-300 | RO608 | Make | 850 | 4/27/2018 |
| 300 | 300 | AA-516 | RO734 | Make | 415 | 5/5/2018 |
| 300 | 300 | AA-516 | RO245 | Bought | 130 | 2/6/2018 |
| 300 | 300 | AA-516 | RO754 | Bought | 874 | 6/9/2018 |
| 300 | 300 | AA-468 | RO120 | Make | 333 | 7/28/2018 |
| 300 | 300 | AA-468 | RO96 | Bought | 279 | 6/11/2018 |
| 300 | 300 | AA-744 | RO576 | Make | 452 | 6/9/2018 |
| 300 | 300 | AA-744 | RO592 | Bought | 967 | 1/16/2018 |
| 300 | 300 | AA-744 | RO104 | Make | 232 | 1/30/2019 |
| 300 | 300 | AA-744 | RO169 | Make | 804 | 2/2/2018 |
| 300 | 130 | AA-785 | RO573 | Make | 616 | 4/1/2018 |
| 300 | 130 | AA-785 | RO139 | Make | 698 | 7/16/2018 |
| 300 | 130 | AA-785 | RO252 | Make | 190 | 8/2/2018 |
| 300 | 130 | AA-785 | RO561 | Make | 453 | 5/13/2018 |
| 300 | 130 | AA-785 | RO775 | Make | 974 | 8/7/2018 |
| 300 | 130 | AA-171 | RO92 | Bought | 493 | 4/1/2018 |
| 300 | 493 | AA-400 | RO4 | Make | 591 | 4/17/2018 |
| 300 | 493 | AA-401 | NULL | NULL | NULL | NULL |
| Now | Starting | From | The | Other | | Tables |
| 300 | 591 | AA-999 | RO1 | Bought | 111 | 4/19/2019 |
| 300 | 591 | AA-111 | RO2 | Bought | 123 | 4/1/2019 |
| 300 | 591 | AA-001 | RO400 | Make | 124 | 5/1/2019 |
| 300 | 124 | AA-313 | RO112 | Bought | 102 | 7/8/2019 |
| etc | etc | etc | etc | etc | etc | etc |
您可以看到订单300
的补货量为130,然后补货量为493
如何使用CONNECT\u BY_ROOT
和CONNECT BY previor
来实现这一点?我尝试过使用如下类似的递归,但这不会产生层次结构
WITH
rec(Root_Order, Order_Number, Requirement_ID, Replenishment_ID, Replenishment_Type, Replenishment_Detail, Replenishment_Date) AS (
SELECT
Orders.Order_Number AS Root_Order,
Orders.Order_Number,
Requirements.Requirement_ID,
Replenishments.Replenishment_ID,
Replenishments.Replenishment_Type,
Replenishments.Replenishment_Detail,
Replenishments.Replenishment_Date
FROM
Orders
LEFT JOIN Requirements ON Orders.Order_Number = Requirements.Order_Number
LEFT JOIN Lookup ON Requirements.Requirement_ID = Lookup.Requirement_ID
LEFT JOIN Replenishments ON Lookup.Replenishment_ID = Replenishments.Replenishment_ID
UNION ALL
SELECT
rec.Order_Number
rec.Replenishment_Details,
Requirements.Requirement_ID,
Replenishments.Replenishment_ID,
Replenishments.Replenishment_Type,
Replenishments.Replenishment_Detail,
Replenishments.Replenishment_Date
FROM
rec
LEFT JOIN Requirements ON Orders.Order_Number = Requirements.Order_Number
LEFT JOIN Lookup ON Requirements.Requirement_ID = Lookup.Requirement_ID
LEFT JOIN Replenishments ON Lookup.Replenishment_ID = Replenishments.Replenishment_ID
)
CYCLE Root_Order, Order_Number, Requirement_ID, Replenishment_ID, Replenishment_Type, Replenishment_Detail, Replenishment_Date SET CYCLE TO 1 DEFAULT 0
SELECT DISTINCT * FROM rec
谢谢从您的输入开始:
with data (
Order_Number , Requirement_ID , Replenishment_ID ,
Replenishment_Type , Replenishment_Detail , Replenishment_Date
) as (
select 300,'AA-300','RO601' ,'Bought', 963, to_date('15-Jul-18','dd-Mon-rr') from dual union all
select 300,'AA-300','RO111' ,'Make', 251, to_date('23-Oct-18','dd-Mon-rr') from dual union all
select 300,'AA-300','RO435' ,'Make', 837, to_date('4-Mar-18','dd-Mon-rr') from dual union all
select 300,'AA-300','RO608' ,'Make', 850, to_date('27-Apr-18','dd-Mon-rr') from dual union all
select 300,'AA-516','RO734' ,'Make', 415, to_date('5-May-18','dd-Mon-rr') from dual union all
select 300,'AA-516','RO245' ,'Bought', 130, to_date('6-Feb-18','dd-Mon-rr') from dual union all
select 300,'AA-516','RO754' ,'Bought', 874, to_date('9-Jun-18','dd-Mon-rr') from dual union all
select 300,'AA-468','RO120' ,'Make', 333, to_date('28-Jul-18','dd-Mon-rr') from dual union all
select 300,'AA-468','RO96' ,'Bought', 279, to_date('11-Jun-18','dd-Mon-rr') from dual union all
select 300,'AA-744','RO576' ,'Make', 452, to_date('9-Jun-18','dd-Mon-rr') from dual union all
select 300,'AA-744','RO592' ,'Bought', 967, to_date('16-Jan-18','dd-Mon-rr') from dual union all
select 300,'AA-744','RO104' ,'Make', 232, to_date('30-Jan-19','dd-Mon-rr') from dual union all
select 300,'AA-744','RO169' ,'Make', 804, to_date('2-Feb-18','dd-Mon-rr') from dual union all
select 500,'AA-100','RO567' ,'Make', 725, to_date('22-Mar-18','dd-Mon-rr') from dual union all
select 500,'AA-100','RO90' ,'Bought', 240, to_date('14-Mar-18','dd-Mon-rr') from dual union all
select 500,'AA-100','RO202' ,'Bought', 185, to_date('26-Feb-18','dd-Mon-rr') from dual union all
select 500,'AA-823','RO764' ,'Bought', 629, to_date('15-Oct-18','dd-Mon-rr') from dual union all
select 500,'AA-823','RO434' ,'Make', 314, to_date('27-Jun-18','dd-Mon-rr') from dual union all
select 500,'AA-823','RO752' ,'Bought', 504, to_date('25-Apr-18','dd-Mon-rr') from dual union all
select 500,'AA-823','RO204' ,'Make', 847, to_date('9-Jul-18','dd-Mon-rr') from dual union all
select 500,'AA-239','RO367' ,'Bought', 652, to_date('14-Feb-18','dd-Mon-rr') from dual union all
select 500,'AA-239','RO732' ,'Bought', 561, to_date('3-Oct-18','dd-Mon-rr') from dual union all
select 130,'AA-785','RO573' ,'Make', 616, to_date('1-Apr-18','dd-Mon-rr') from dual union all
select 130,'AA-785','RO139' ,'Make', 698, to_date('16-Jul-18','dd-Mon-rr') from dual union all
select 130,'AA-785','RO252' ,'Make', 190, to_date('2-Aug-18','dd-Mon-rr') from dual union all
select 130,'AA-785','RO561' ,'Make', 453, to_date('13-May-18','dd-Mon-rr') from dual union all
select 130,'AA-785','RO775' ,'Make', 974, to_date('7-Aug-18','dd-Mon-rr') from dual union all
select 130,'AA-171','RO92' ,'Bought', 493, to_date('1-Apr-18','dd-Mon-rr') from dual union all
select 200,'AA-171','RO532' ,'Make', 727, to_date('17-May-18','dd-Mon-rr') from dual union all
select 200,'AA-337','RO29' ,'Make', 402, to_date('1-Jun-18','dd-Mon-rr') from dual union all
select 200,'AA-337','RO725' ,'Make', 892, to_date('9-Mar-18','dd-Mon-rr') from dual union all
select 200,'AA-533','RO216' ,'Bought', 637, to_date('1-Jun-18','dd-Mon-rr') from dual union all
select 100,'AA-100', NULL , NULL, NULL, NULL from dual union all
select 100,'AA-100','RO438' ,'Make', 125, to_date('19-Mar-18','dd-Mon-rr') from dual union all
select 493,'AA-400','RO4', 'Bought', 591, to_date('17-Apr-18','dd-Mon-rr') from dual union all
select 493,'AA-401', NULL , NULL, NULL, NULL from dual
)
select connect_by_root(order_number) root_order, data.*, level lvl
from data
start with order_number not in (
select replenishment_detail from data where replenishment_detail is not null
)
connect by order_number = prior replenishment_detail
order siblings by order_number, replenishment_detail;
ROOT_ORDER ORDER_NUMBER REQUIR REPLE REPLEN REPLENISHMENT_DETAIL REPLENISHMENT_DATE LVL
---------- ------------ ------ ----- ------ -------------------- ------------------- ----------
100 100 AA-100 RO438 Make 125 2018-03-19 00:00:00 1
100 100 AA-100 1
200 200 AA-337 RO29 Make 402 2018-06-01 00:00:00 1
200 200 AA-533 RO216 Bought 637 2018-06-01 00:00:00 1
200 200 AA-171 RO532 Make 727 2018-05-17 00:00:00 1
200 200 AA-337 RO725 Make 892 2018-03-09 00:00:00 1
300 300 AA-516 RO245 Bought 130 2018-02-06 00:00:00 1
300 130 AA-785 RO252 Make 190 2018-08-02 00:00:00 2
300 130 AA-785 RO561 Make 453 2018-05-13 00:00:00 2
300 130 AA-171 RO92 Bought 493 2018-04-01 00:00:00 2
300 493 AA-400 RO4 Bought 591 2018-04-17 00:00:00 3
300 493 AA-401 3
300 130 AA-785 RO573 Make 616 2018-04-01 00:00:00 2
300 130 AA-785 RO139 Make 698 2018-07-16 00:00:00 2
300 130 AA-785 RO775 Make 974 2018-08-07 00:00:00 2
300 300 AA-744 RO104 Make 232 2019-01-30 00:00:00 1
300 300 AA-300 RO111 Make 251 2018-10-23 00:00:00 1
300 300 AA-468 RO96 Bought 279 2018-06-11 00:00:00 1
300 300 AA-468 RO120 Make 333 2018-07-28 00:00:00 1
300 300 AA-516 RO734 Make 415 2018-05-05 00:00:00 1
300 300 AA-744 RO576 Make 452 2018-06-09 00:00:00 1
300 300 AA-744 RO169 Make 804 2018-02-02 00:00:00 1
300 300 AA-300 RO435 Make 837 2018-03-04 00:00:00 1
300 300 AA-300 RO608 Make 850 2018-04-27 00:00:00 1
300 300 AA-516 RO754 Bought 874 2018-06-09 00:00:00 1
300 300 AA-300 RO601 Bought 963 2018-07-15 00:00:00 1
300 300 AA-744 RO592 Bought 967 2018-01-16 00:00:00 1
500 500 AA-100 RO202 Bought 185 2018-02-26 00:00:00 1
500 500 AA-100 RO90 Bought 240 2018-03-14 00:00:00 1
500 500 AA-823 RO434 Make 314 2018-06-27 00:00:00 1
500 500 AA-823 RO752 Bought 504 2018-04-25 00:00:00 1
500 500 AA-239 RO732 Bought 561 2018-10-03 00:00:00 1
500 500 AA-823 RO764 Bought 629 2018-10-15 00:00:00 1
500 500 AA-239 RO367 Bought 652 2018-02-14 00:00:00 1
500 500 AA-100 RO567 Make 725 2018-03-22 00:00:00 1
500 500 AA-823 RO204 Make 847 2018-07-09 00:00:00 1
在WITH DATA子句中,替换联接。排序将把每个“根”顺序的所有行放在一起,但在每个“根”中,层次结构将变为“深度优先”,因此您可以看到级别之间的直接关系
致以最良好的祝愿,
斯图·阿什顿(Stew Ashton)我想你在寻找类似的东西:
with rec(root_order, order_number, requirement_id, replenishment_id, replenishment_type,
replenishment_detail, replenishment_date)
as (
-- anchor member
select
orders.order_number as root_order,
orders.order_number,
requirements.requirement_id,
replenishments.replenishment_id,
replenishments.replenishment_type,
replenishments.replenishment_detail,
replenishments.replenishment_date
from orders
join requirements on orders.order_number = requirements.order_number
left join lookup on requirements.requirement_id = lookup.requirement_id
left join replenishments on lookup.replenishment_id = replenishments.replenishment_id
union all
-- recursive member
select rec.root_order,
requirements.order_number,
requirements.requirement_id,
replenishments.replenishment_id,
replenishments.replenishment_type,
replenishments.replenishment_detail,
replenishments.replenishment_date
from rec
join requirements on rec.replenishment_detail = requirements.order_number
left join lookup on requirements.requirement_id = lookup.requirement_id
left join replenishments on lookup.replenishment_id = replenishments.replenishment_id
)
select *
from rec
order by root_order, order_number, requirement_id;
锚定成员本质上是您的原始查询,除了它添加根顺序
之外,我还将第一个加入到一个内部查询中,以稍微减少噪音(原始查询中的87行中有很多只有顺序编号
,其他所有内容都为空)
然后,递归成员将rec.requirement\u detail
(子订单号)加入到requirements.order\u number
中,以在层次结构中遍历。它不需要再次引用实际的orders表(除非您确实需要该表中的其他字段,在这种情况下,包含它是很简单的)
使用生成65行输出的示例数据,包括:
ROOT_ORDER ORDER_NUMBER REQUIR REPLE REPLEN REPLENISHMENT_DETAIL REPLENISHM
---------- ------------ ------ ----- ------ -------------------- ----------
...
300 130 AA-171 RO532 Make 727 2018-05-17
300 130 AA-171 RO92 Bought 493 2018-04-01
300 130 AA-785 RO573 Make 616 2018-04-01
300 130 AA-785 RO561 Make 453 2018-05-13
300 130 AA-785 RO775 Make 974 2018-08-07
300 130 AA-785 RO139 Make 698 2018-07-16
300 130 AA-785 RO252 Make 190 2018-08-02
300 300 AA-300 RO601 Bought 963 2018-07-15
300 300 AA-300 RO111 Make 251 2018-10-23
300 300 AA-300 RO435 Make 837 2018-03-04
300 300 AA-300 RO608 Make 850 2018-04-27
300 300 AA-468 RO96 Bought 279 2018-06-11
300 300 AA-468 RO120 Make 333 2018-07-28
300 300 AA-516 RO754 Bought 874 2018-06-09
300 300 AA-516 RO245 Bought 130 2018-02-06
300 300 AA-516 RO734 Make 415 2018-05-05
300 300 AA-744 RO169 Make 804 2018-02-02
300 300 AA-744 RO576 Make 452 2018-06-09
300 300 AA-744 RO592 Bought 967 2018-01-16
300 300 AA-744 RO104 Make 232 2019-01-30
300 493 AA-400 RO4 Bought 591 2018-04-17
300 493 AA-401
...
基于你的原创
请注意,它还独立地包含“子”命令:
...
130 130 AA-171 RO92 Bought 493 2018-04-01
130 130 AA-171 RO532 Make 727 2018-05-17
130 130 AA-785 RO775 Make 974 2018-08-07
130 130 AA-785 RO561 Make 453 2018-05-13
130 130 AA-785 RO252 Make 190 2018-08-02
130 130 AA-785 RO573 Make 616 2018-04-01
130 130 AA-785 RO139 Make 698 2018-07-16
130 493 AA-400 RO4 Bought 591 2018-04-17
130 493 AA-401
...
493 493 AA-400 RO4 Bought 591 2018-04-17
493 493 AA-401
...
等等。您可以从特定的目标订单开始(即,让锚定成员拥有where orders.order_number=300
),但不清楚这是否是您想要的。如果不是,并且您不想看到较低的订单,那么您需要一种识别顶级订单的方法。一种方法是通过添加一个不存在(…)
过滤器,排除任何显示为任何补货_详细信息
值的订单:
with rec(root_order, order_number, requirement_id, replenishment_id, replenishment_type,
replenishment_detail, replenishment_date)
as (
-- anchor member
select
orders.order_number as root_order,
orders.order_number,
requirements.requirement_id,
replenishments.replenishment_id,
replenishments.replenishment_type,
replenishments.replenishment_detail,
replenishments.replenishment_date
from orders
join requirements on orders.order_number = requirements.order_number
left join lookup on requirements.requirement_id = lookup.requirement_id
left join replenishments on lookup.replenishment_id = replenishments.replenishment_id
where not exists (
select *
from replenishments
where replenishment_detail = orders.order_number
)
union all
-- recursive member
select rec.root_order,
requirements.order_number,
requirements.requirement_id,
replenishments.replenishment_id,
replenishments.replenishment_type,
replenishments.replenishment_detail,
replenishments.replenishment_date
from rec
join requirements on rec.replenishment_detail = requirements.order_number
left join lookup on requirements.requirement_id = lookup.requirement_id
left join replenishments on lookup.replenishment_id = replenishments.replenishment_id
)
select *
from rec
order by root_order, order_number, requirement_id;
现在只得到54行,不包括上面的130/493/etc.根订单行
由于您实际询问的是分层查询,而不是递归查询,因此以下是如何做到这一点:
with cte (order_number, requirement_id, replenishment_id, replenishment_type,
replenishment_detail, replenishment_date, is_root_order)
as (
select
orders.order_number,
requirements.requirement_id,
replenishments.replenishment_id,
replenishments.replenishment_type,
replenishments.replenishment_detail,
replenishments.replenishment_date,
case when exists (
select *
from replenishments
where replenishment_detail = orders.order_number
) then 'N' else 'Y' end
from orders
join requirements on orders.order_number = requirements.order_number
left join lookup on requirements.requirement_id = lookup.requirement_id
left join replenishments on lookup.replenishment_id = replenishments.replenishment_id
)
select connect_by_root(order_number) as root_order,
order_number, requirement_id, replenishment_id, replenishment_type,
replenishment_detail, replenishment_date
from cte
start with is_root_order = 'Y'
connect by order_number = prior replenishment_detail;
CTE同样是您的原始查询,它有一个case表达式和exists子句来决定每个订单是否是一个“根”订单,就像以前一样,但现在是一个标志,而不是一个过滤器。然后,分层查询相当简单,在其以
子句开始时使用该标志
还有一个
(我刚刚意识到@Studashton说的就是这么做的;我的CTE本质上是他的“替换连接”步骤。唯一的另一个真正的区别是,他将标志计算直接移动到了以
开始的子句中,这实际上可能会稍微有效一些,因为它不必点击补货。)s
再次显示表格…)
一般来说,我更喜欢递归CTE方法,但层次化方法仅因其简洁而吸引人。不过,您可能希望将这两种方法的性能与实际数据进行比较。最好将起始数据显示为四个基表,以使关系和层次更清晰。(可能是在一个?进一步简化?)我正在努力了解您的起始数据和结果是如何关联的。尽管您的递归CTE似乎没有任何意义,但这两个分支有不同的投影,锚分支没有过滤器,递归分支在连接条件中没有引用rec
(或where子句,该子句既没有也没有)。我担心的是,通过显示每个表中的数据,我的问题太长了。我有一个基本的ER模型,我用它编辑了这个问题。我可以尝试生成一个db或sql FIDLE。让我添加一点细节,看看它是否有助于澄清问题。此外,我决不是暗示使用wo进行递归rks…我迷路了,正在尝试解决这个问题…并且没有定义rec.Details
。我们只能猜测…是的,但是我们必须解构查询结果以获得基础数据,这样我们就可以创建一个从基础数据运行的递归查询…ER可能没有帮助,因为查询已经显示了关系.Fixed@Serg。如前所述,我试图欺骗很多人。很抱歉造成混淆。这可能超出了原始问题的范围,但我想请您帮助,因为这看起来很棒。“顶级”的定义order将是Orders
表的某个子集。在本例中,如果我希望我的顶层仅为以2开头的Orders,那么在您的查询中如何识别它?@JerryM.-withwhere to_char(Orders.order_number)类似于锚定成员中的“2%”
。您的数据在根订单200中获得16行。但不确定它是否完全解决了重复的子问题,除非您的实际数据完全不同。这很尴尬