簡體   English   中英

使用 CONNECT BY PRIOR 進行分層查詢 - Oracle SQL

[英]Using CONNECT BY PRIOR for a hierarchical query - 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        |

在這里你可以看到訂單300有 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 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 子句中,替換您的連接。 排序會將每個“根”順序的所有行放在一起,但在每個“根”內,層次結構將“深度優先”,因此您可以看到級別之間的直接關系。

最好的問候, 燉阿什頓

我認為你正在尋找類似的東西:

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並且我將第一個 join 加入了內部以稍微減少噪音(原始的 87 行中的很多只有order_number其他所有內容為空)。

然后遞歸成員將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 ),但不清楚這是否是你想要的。 如果不是,並且您也不希望自己看到較低的訂單,那么您需要一種方法來識別頂級訂單。 一種方法可能是通過添加not exists(...)過濾器來排除任何顯示為任何replenishment_detail值的訂單:

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/等。 上面的根順序行。

數據庫<>小提琴


由於您實際上詢問的是分層查詢而不是遞歸查詢,因此您可以這樣做:

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 方法,但分層方法在這里很有吸引力,只是因為它的簡潔性。 不過,您可能希望將兩種方法的性能與您的真實數據進行比較。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM