【发布时间】:2021-05-14 08:06:47
【问题描述】:
我正在寻找一种在 SQL Server 中使用 Partition by Over 的巧妙方法。
我在 SQL Server 中有 3 个表(下面的所有 *_id 列都只是伪主键)
- PO (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 | qty | dely_no | dely_qty |
|---|---|---|---|---|
| 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 | OrdPOQty | DelyPOQty | po_item_no | OrdItemQty | delyItemQty | dely_no | dely_qty |
|---|---|---|---|---|---|---|---|
| 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'
【问题讨论】:
-
PARTITION BY基本上就是GROUP BY,DISTINCT在PARTITION BY子句之后就不需要了。 -
“所以在这个例子中,PO1 的总订购数量是 650,但总交付数量是 663。” - 我可能很厚,但是这些数字在哪里从哪里来?
-
PO1 有 3 项:PoI11 (Ordered qty = 300), PoI12 (Ordered qty = 100), PoI13 (Ordered qty = 250) 所以总共是 650。但是如果在表中添加 dely_qty 列1 然后是 663。基本上 PoI11 在第 1、2、3 号交付中已经交付了 3 次。PoI12 仅交付了 1 次。 PoI13 交付了 2 次。
标签: sql sql-server window-functions