簡體   English   中英

如何對不同值求和 OVER (PARTITION BY DISTINCT)

[英]How to sum OVER (PARTITION BY DISTINCT) for Distinct Values

我正在尋找一種在 SQL 服務器中使用Partition by Over的巧妙方法。

我在 SQL 服務器中有 3 個表(下面的所有*_id列都只是偽主鍵)

  • 采購訂單(po_id,po_no);
  • PO_ITEM (po_item_id, po_id, po_item_no, 數量); // 存儲 PO ITEM 的訂購數量
  • PO_ITEM_DELY (po_item_dely_id, po_item_id, dely_no, dely_qty); // 存儲每個交貨編號的每個 PO 項目的交貨數量。
select
    po.po_no, pt.po_item_no, pt.qty, pd.dely_no, pd.dely_qty
from 
    PO
inner join 
    PO_ITEM pt on pt.po_id = po.po_id
inner join 
    PO_ITEM_DELY pd on pd.po_item_id = pt.po_item_id
where 
    po.po_no = 'PO1'

此 SQL 查詢的結果供參考:

po_no po_item_no 數量 dely_no 延遲數量
PO1 PoI11 300 1 210
PO1 PoI11 300 2 48
PO1 PoI11 300 3 55
PO1 PoI12 100 1 100
PO1 PoI13 250 1 150
PO1 PoI13 250 2 100

因此,在此示例中,PO1 的總訂購數量為 650,但總交付數量為 663。

期望的結果:

po_no 訂購量 交貨數量 po_item_no 訂單項數量 交貨數量 dely_no 延遲數量
PO1 650 663 PoI11 300 313 1 210
PO1 650 663 PoI11 300 313 2 48
PO1 650 663 PoI11 300 313 3 55
PO1 650 663 PoI12 100 100 1 100
PO1 650 663 PoI13 250 250 1 150
PO1 650 663 PoI13 250 250 2 100

現在我可以通過使用子查詢來完成這項任務:

with poOrdQtyDtl as (
-- Form a Join between PO and PO_ITEM to get Total Ordered Qty Per PO
select
    po.po_id,
    po.po_no,
    sum(pt.qty) OrdPoQty
from PO
inner join PO_ITEM pt on pt.po_id = po.po_id
group by po.po_id, po.po_no
)
select
    poOrdQtyDtl.po_no [PO No.],
    poOrdQtyDtl.OrdPoQty [Ordered Qty For PO],
    sum(itemDely.currDelyQty) over (partition by poOrdQtyDtl.po_no) as [Delivered Qty For Po],
    itemDely.po_item_no [Item No.],
    itemDely.OrdItemQty [Ordred Item Qty],
    itemDely.DelItemQty [Delivered Item Qty],
    itemDely.dely_no [Dely No.],
    itemDely.currDelyQty [Item Qty Delivered in Current Dely]
from poOrdQtyDtl
inner join (
-- Join PO_ITEM and PO_ITEM_DELY to get Item Quantity details
select
    pt.po_id,
    pt.po_item_id,
    pt.po_item_no,
    pt.qty OrdItemQty,
    sum(pd.dely_qty) over (partition by pt.po_item_no) DelItemQty,
    pd.dely_no,
    pd.dely_qty currDelyQty
from PO_ITEM pt
inner join PO_ITEM_DELY pd on pd.po_item_id = pt.po_item_id
) itemDely on itemDely.po_id = poOrdQtyDtl.po_id
WHERE poOrdQtyDtl.po_no = 'PO1'
;

但是,我只是想知道是否有一種更簡單的方法可以通過更巧妙地應用over partition by子句來進行求和。 主要挑戰在於下面的查詢,因為我不能在partition by子句中使用distinct

select
    po.po_no,
    -- sum (pt.qty) over (partition by distinct po.po_no, pt.po_item_no) TotPoQOrd, -- INCORRECT
    sum (pt.qty) over (partition by po.po_no, pt.po_item_no) TotPoQOrd,
    sum(pd.dely_qty) over (partition by po.po_no) TotPoQDely,
    pt.po_item_no,
    pt.qty,
    sum(pd.dely_qty) over (partition by po.po_no, pt.po_item_no) TotItemQ,
    pd.dely_no,
    pd.dely_qty
from PO
inner join PO_ITEM pt on pt.po_id = po.po_id
inner join PO_ITEM_DELY pd on pd.po_item_id = pt.po_item_id
where po.po_no = 'PO1'

使用多個不同的 window 規格來解決這個問題:

    select
      x.po_no, 

      x.OrdPOQty,
      SUM(pd.dely_qty) OVER(PARTITION BY x.po_no) as DelyPOQty,
      
      x.po_item_no,

      x.OrdItemQty,
      SUM(pd.dely_qty) OVER(PARTITION BY x.po_no, x.po_item_no) as DelyItemQty,
       
      x.qty, 
      pd.dely_no, 
      pd.dely_qty
    from 
      ( 
        SELECT 
          po.po_id, po.po_no, pt.po_item_id, pt.po_item_no, pt.qty, 
          SUM(pt.qty) OVER(PARTITION BY po.po_no) as OrdPOQty, 
          SUM(pt.qty) OVER(PARTITION BY po.po_no, pt.po_item_no) as OrdItemQty
        FROM PO inner join PO_ITEM pt on pt.po_id = po.po_id
      ) x
      inner join PO_ITEM_DELY pd on pd.po_item_id = x.po_item_id
    where 
      x.po_no = 'PO1'

從技術上講partition by po_no是不必要的,因為 where 子句確保只有一個,但我把它留了下來,以防你想擴展查詢以考慮多個po_no

如果您總是只查詢一個po_no

    select
      x.po_no, 

      x.OrdPOQty,
      SUM(pd.dely_qty) OVER() as DelyPOQty,
      
      x.po_item_no,

      x.OrdItemQty,
      SUM(pd.dely_qty) OVER(PARTITION BY x.po_item_no) as DelyItemQty,
       
      x.qty, 
      pd.dely_no, 
      pd.dely_qty
    from 
      ( 
        SELECT 
          po.po_id, po.po_no, pt.po_item_id, pt.po_item_no, pt.qty, 
          SUM(pt.qty) OVER(PARTITION BY po.po_no) as OrdPOQty, 
          SUM(pt.qty) OVER(PARTITION BY po.po_no, pt.po_item_no) as OrdItemQty
        FROM PO inner join PO_ITEM pt on pt.po_id = po.po_id
      ) x
      inner join PO_ITEM_DELY pd on pd.po_item_id = x.po_item_id
    where 
      x.po_no = 'PO1'

想知道是否有更巧妙地應用 over partition by 子句來進行求和的更簡單方法

好吧,基本上使用基本形式,您最終會得到 N 行重復,並且您可以計算重復次數並將組中值的總和除以組的重復次數,因此您將值相加他們原來的三分之一,但重復了 3 次以獲得相同的總和。但我確實覺得這比在沒有笛卡爾積的水平上進行求和和計數更混亂,然后這個結果就被執行了並重復..

或者我們可以只計算其中一個項目,假設每個項目至少有一個交付 #1:

select
  po.po_no, 

  SUM(CASE WHEN pd.dely_no = 1 THEN pt.qty ELSE 0 END) OVER(PARTITION BY po.po_no) as OrdPOQty,
  SUM(pd.dely_qty) OVER(PARTITION BY po.po_no) as DelyPOQty,
  
  pt.po_item_no,

  SUM(CASE WHEN pd.dely_no = 1 THEN pt.qty ELSE 0 END) OVER(PARTITION BY po.po_no, pt.po_item_no) as OrdItemQty,
  SUM(pd.dely_qty) OVER(PARTITION BY po.po_no, pt.po_item_no) as DelyItemQty,
   
  pt.qty, 
  pd.dely_no, 
  pd.dely_qty
from 
  PO
  inner join PO_ITEM pt on pt.po_id = po.po_id
  inner join PO_ITEM_DELY pd on pd.po_item_id = pt.po_item_id
where 
  po.po_no = 'PO1'

如果您添加另一個表,導致pd.dely_no每個po/po+item分區的重復值為 1,那么您需要擴展 CASE 邏輯

暫無
暫無

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

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