![](/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.