使用CONNECT BY PRIOR进行分层查询-Oracle SQL

奇迹警告

我当前正在处理一项要求进行分层查询的需求,而这似乎是我无法理解的。

要求是:对于给定的一组订单,找出所有要求,以及补充这些要求的内容。然后,在补货是一种MAKE类型(即另一个订单)的情况下,找出其所有需求和补货等。

这是一个dbfiddle,其中包含所有数据和一些示例查询

小提琴结尾处的结果查询实际上是在说:对于订单x,这是其所有要求。对于这些需求中的每一个,下面是计划对其进行补充的内容。

我现在需要做的是对所有make类型的补货,我基本上需要继续进行此过程,方法是联接到那些表,提取要补充的那些补货,依此类推,以此类推,但要在保持跟踪的情况下进行。顶级订单。

我希望将其转换为如下所示的数据集:

| 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        |

您可以在其中看到Order300的补货数量为130,然后补货为493。

如何使用CONNECT_BY_ROOTCONNECT BY PRIOR实现这一目标?我已经尝试过WITH像下面这样的递归,但是不会产生层次结构。

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 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;

锚成员本质上是您的原始查询,除了它添加,root_order并且我使第一个联接成为内部查询以降低噪音(原始的87行中很多order_number只有null)。

然后,递归成员加入rec.replenishment_detail(子订单号)requirements.order_number以遍历层次结构。不需要再次引用实际的订单表(除非您实际上想要从中获取其他字段,在这种情况下,将其包含在内很简单)。

使用您的样本数据可以产生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                                             
...

db <> fiddle根据您的原始版本。

请注意,尽管它还独立包含“子”订单:

...
       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),但是尚不清楚这是否是您想要的。如果不是这样,并且您也不想自己查看较低的订单,那么您需要一种方法来识别顶级订单。一种方法是replenishment_detail通过添加not exists(...)过滤器来排除显示为任何值的所有订单

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。上面的根顺序行。

db <>小提琴


由于您实际上询问的是分层查询而不是递归查询,因此可以执行以下操作:

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子句,用于像以前一样确定每个订单是否为“根”订单,但现在作为标志而不是过滤器。然后,在其starts with子句中使用该标志,分层查询就相当简单

另一个db <> fiddle

(我刚刚意识到这几乎是@StewAshton所说的;我的CTE本质上是他的“替换您的联接”步骤。唯一的真正不同是他将标志计算直接移到了starts with子句中,实际上效率更高,因为它不必replenishments再次桌子...)

我通常更喜欢递归CTE方法,但层次结构方法在此仅出于其简洁性就很有吸引力。但是,您可能希望将两种方法的性能与实际数据进行比较。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章