[英]Lossless / Fair Share Division in SQL
在几种情况下,我希望使用PostgreSQL能够将一个整数除以另一个整数并完成三件事:
我现在要处理的特定问题是每月有这样的数量:
Month Part Qty
--------- --------- -----
1/1/2016 ABC 10
2/1/2016 ABC 9
就我成功而言,这已经达到了我的前两个目标,但没有达到我的第三个目标:
with weekly_buckets as (
select generate_series (0, 3) as week_number
)
select
p.month_date + 7 * w.week_number as week_date,
p.part_number,
case w.week_number
when 0 then p.qty / 4
when 1 then p.qty / 4
when 2 then p.qty / 4
when 3 then p.qty - 3 * (p.qty / 4)
end as qty
from
part_demand p
cross join weekly_buckets w
导致:
Week Part Qty
--------- --------- -----
1/1/2016 ABC 2
1/8/2016 ABC 2
1/15/2016 ABC 2
1/22/2016 ABC 4
因此,最后一周的曲棍球棒效应为4。 我可以用天花板代替地板,但是在3、3、3、1时情况会更糟。
理想情况下,价差看起来像2、3、2、3或3、2、3、2。 这就是我所说的公平份额利差。 如果在数学上有一个更正确的术语,请赐教。
作为参考,这些数量代表每月的预测,我们正在尝试确定实际订单是否在预期目标之前,之后或之后。
另外,如果我能解决这个问题,我可以利用逻辑来做同样的事情来为年度数量创建月度存储桶。
作为最后一个例子,如果我看到这样的话:
Month Part Qty
--------- --------- -----
1/1/2016 ABC 1
理想情况下,只有一个非零值的星期是第2周或第3周。这确实没有关系,但是如果您想知道将如何处理低值,这就是我的初衷。
您可以使用窗口函数来分配值。 这是您的第一个示例:
with b as (
select generate_series(1, 4) as i, 10 as amt
),
bb as (
select b.*,
count(*) over () as numbuckets,
row_number() over (order by i) as rn,
amt % (count(*) over () ) as remainder
from b
)
select bb.*,
(amt / numbuckets +
(case when rn <= remainder then 1 else 0 end)
) as partitioned
from bb;
这个想法是为每个存储桶分配amt / numbuckets
。 然后使用row_number()
将剩余部分分布到各个存储桶中。 如果您希望这些值随机散布,请使用order by random()
定义rn
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.