根据收入份额将每月价值拆分为天数和国家/地区

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) 拆分为国家 DEFR 每天 > 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/…

以上是关于根据收入份额将每月价值拆分为天数和国家/地区的主要内容,如果未能解决你的问题,请参考以下文章

在 PHP 中根据产品和买家国家/地区计算收入

如何从 JSON 数据中提取国家/地区

Mysql,重塑数据从长/高到宽

计算每个国家/地区每天的销售份额

如何根据总订单价值和邮政组获取报告

根据用户输入值增加表中的列