![](/img/trans.png)
[英]How to run SUM() OVER PARTITION BY for COUNT DISTINCT
[英]How to sum OVER (PARTITION BY DISTINCT) for Distinct Values
我正在尋找一種在 SQL 服務器中使用Partition by Over
的巧妙方法。
我在 SQL 服務器中有 3 個表(下面的所有*_id
列都只是偽主鍵)
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.