根据收入份额将每月价值拆分为天数和国家/地区
Posted
技术标签:
【中文标题】根据收入份额将每月价值拆分为天数和国家/地区【英文标题】:Split fix monthly value to days and countries based on revenue shares 【发布时间】:2021-01-14 12:48:49 【问题描述】:DB-Fiddle:
CREATE TABLE sales (
id int auto_increment primary key,
country VARCHAR(255),
sales_date DATE,
sales_volume INT,
fix_costs INT
);
INSERT INTO sales
(country, sales_date, sales_volume, fix_costs
)
VALUES
("DE", "2020-12-01", "500", "0"),
("NL", "2020-12-01", "320", "0"),
("FR", "2020-12-01", "350", "0"),
("DE", "2020-12-02", "700", "0"),
("NL", "2020-12-02", "420", "0"),
("FR", "2020-12-02", "180", "0"),
("DE", "2020-12-03", "0", "0"),
("NL", "2020-12-03", "0", "0"),
("FR", "2020-12-03", "0", "0"),
("None", "2020-12-31", "0", "2000");
预期结果:
sales_date | country | sales_volume | fix_costs
-------------|--------------|------------------|------------------------------------------
2020-12-01 | DE | 500 | 37.95 (=2000/31 = 64.5 * 0.59)
2020-12-01 | FR | 350 | 26.57 (=2000/31 = 64.5 * 0.41)
2020-12-01 | NL | 320 | 0.00
-------------|--------------|------------------|------------------------------------------
2020-12-02 | DE | 700 | 51.32 (=2000/31 = 64.5 * 0.8)
2020-12-02 | FR | 180 | 13.20 (=2000/31 = 64.5 * 0.2)
2020-12-02 | NL | 420 | 0.00
-------------|--------------|------------------|------------------------------------------
2020-12-03 | DE | 0 | 32.26 (=2000/31 = 64.5 * 0.5)
2020-12-03 | FR | 0 | 32.26 (=2000/31 = 64.5 * 0.5)
2020-12-03 | NL | 0 | 0.00
-------------|--------------|------------------|-------------------------------------------
在上面的结果中,我想根据 daily 将每月的 fix_cost
值 (in this case 2000)
拆分为国家 DE
和 FR
每天 > sales_volume
在所选countries
的每个 中。到目前为止,我已经使用了这个question 的解决方案,效果很好:
SELECT
sales_date,
country,
SUM(sales_volume),
(CASE WHEN country <> 'NL'
THEN SUM(SUM(fix_costs)) over(partition BY year(sales_date), month(sales_date))
/ day(last_day(sales_date))
* SUM(sales_volume)
/ SUM(CASE WHEN country <> 'NL' THEN SUM(sales_volume) ELSE 0 END) over(partition BY sales_date)
END) AS fix_cost_per_day
FROM sales
GROUP BY 1,2;
但是,正如您在 2020-12-03
上的数据中看到的那样,根本没有销售。
因此,上面的查询无法在这一天将每日fix_costs
拆分到每个国家/地区。
为了解决这个问题,我想修改查询,这样万一有一天没有sales_volume
,值应该被拆分50/50。
我必须如何修改查询才能实现这一点?
【问题讨论】:
第三天的数据从哪里来? 每月值为 2000,我将这个值除以当月的天数。在上述情况下,这是 31,因为它是 12 月。因此,64.5 是需要分配给每个月的每一天的值。现在,这个每日价值会根据每天的 sales_volume 分配给每个国家/地区。如果国家/地区没有 sales_volume,则应按 50/50 划分。 我看不出您是如何达到预期结果的,样本源数据中没有任何国家/地区在 2020-12-03 有 sales_volume,那么您在哪里想到了 2020 年预期结果中的 sales_volume 数字-12-03? 对于没有任何 sales_volume 的日期,我想将每日价值 64.5 拆分为每个国家/地区 50/50。因此,在上例中,DE 和 FR 为 32.26。 换句话说,您的预期结果与样本输入没有相似之处..即使忽略固定成本 【参考方案1】:如果我理解正确,你。想在每个月的每一天分配 2,000 个,并分配给除'NL'
以外的所有国家/地区。
这是带有窗口函数的算术:
使用last_day()
获取当月的天数。
使用窗口函数计算除'NL'
之外的每个国家/地区的收入比例。
使用条件逻辑,所以'NL'
是特殊的。
作为SELECT
查询:
select s.*,
(case when country = 'NL' then 0
else ((2000 / day(last_day(sales_date))) *
sales_volume / nullif(sum(case when country <> 'NL' then sales_volume end) over (partition by sales_date), 0)
)
end) as imputed_fixed_costs
from sales s
order by id;
注意:2000
使代码更清晰,但显然您可以使用以下命令将其输入到查询中:
from sales s cross join
(select sum(fix_costs) as fixed_costs
from sales
where country = 'None'
) f
Here 是一个 dbfiddle。
如果您真的想更改数据,这很容易合并到update
,尽管问题中的示例查询是select
。
处理没有销售的月份:
select s.*,
(case when country = 'NL'
then 0
when sum(case when country <> 'NL' then sales_volume end) over (partition by sales_date) > 0
then ((2000 / day(last_day(sales_date))) *
sales_volume / nullif(sum(case when country <> 'NL' then sales_volume end) over (partition by sales_date), 0)
)
else (2000 / day(last_day(sales_date))) * 1 / sum(country <> 'NL') over (partition by sales_date)
end) as imputed_fixed_costs
from sales s
order by id;
【讨论】:
当我运行 DB-Fiddle 时,我得到 2020-12-03 的 0,但对于 DE 和 FR,它应该是 32.26。这些国家/地区没有销售价值,因此我希望将 64.5 的每日价值按 50/50 分配给每个国家/地区。 @Michi 。 . .这实际上只是对查询的一个小调整。 仅用于我的文档:dbfiddle.uk/…以上是关于根据收入份额将每月价值拆分为天数和国家/地区的主要内容,如果未能解决你的问题,请参考以下文章