将每月固定值拆分为 Redshift 中的天数和国家/地区
Posted
技术标签:
【中文标题】将每月固定值拆分为 Redshift 中的天数和国家/地区【英文标题】:Split monthly fix value to days and countries in Redshift 【发布时间】:2021-03-03 14:33:45 【问题描述】:DB-Fiddle
CREATE TABLE sales (
id SERIAL PRIMARY KEY,
country VARCHAR(255),
sales_date DATE,
sales_volume DECIMAL,
fix_costs DECIMAL
);
INSERT INTO sales
(country, sales_date, sales_volume, fix_costs
)
VALUES
('DE', '2020-01-03', '500', '2000'),
('NL', '2020-01-03', '320', '2000'),
('FR', '2020-01-03', '350', '2000'),
('None', '2020-01-31', '0', '2000'),
('DE', '2020-02-15', '0', '5000'),
('NL', '2020-02-15', '0', '5000'),
('FR', '2020-02-15', '0', '5000'),
('None', '2020-02-29', '0', '5000'),
('DE', '2020-03-27', '180', '4000'),
('NL', '2020-03-27', '670', '4000'),
('FR', '2020-03-27', '970', '4000'),
('None', '2020-03-31', '0', '4000');
预期结果:
sales_date | country | sales_volume | used_fix_costs
-------------|--------------|------------------|------------------------------------------
2020-01-03 | DE | 500 | 37.95 (= 2000/31 = 64.5 x 0.59)
2020-01-03 | FR | 350 | 26.57 (= 2000/31 = 64.5 x 0.41)
2020-01-03 | NL | 320 | 0.00
-------------|--------------|------------------|------------------------------------------
2020-02-15 | DE | 0 | 86.21 (= 5000/28 = 172.4 x 0.50)
2020-02-15 | FR | 0 | 86.21 (= 5000/28 = 172.4 x 0.50)
2020-02-15 | NL | 0 | 0.00
-------------|--------------|------------------|------------------------------------------
2020-03-27 | DE | 180 | 20.20 (= 4000/31 = 129.0 x 0.16)
2020-03-27 | FR | 970 | 108.84 (= 4000/31 = 129.0 x 0.84)
2020-03-27 | NL | 670 | 0.00
-------------|--------------|------------------|-------------------------------------------
预期结果中的used_fix_costs
列计算如下:
第 1 步) 从后续步骤中排除国家/地区 NL
,但它仍应以值 0
出现在结果中。
第 2 步) 获取每月 fix_costs 的每日费率。(2000/31 = 64.5; 5000/29 = 172.4; 4000/31 = 129.0)
第 3 步) 根据 DE 和 FR 国家/地区在 sales_volume 中的份额将每日价值拆分。 (500/850 = 0.59; 350/850 = 0.41; 180/1150 = 0.16; 970/1150 = 0.84)
第 4 步) 如果 sales_volume 为 0
,则每日费率将 50/50
拆分为 DE 和 FR,如 2020-02-15
所示。
我目前正在使用此查询来获得预期的结果:
SELECT
s.sales_date,
s.country,
s.sales_volume,
s.fix_costs,
(CASE WHEN country = 'NL' THEN 0
/* Exclude NL from fixed_costs calculation */
WHEN SUM(CASE WHEN country <> 'NL' THEN sales_volume ELSE 0 END) OVER (PARTITION BY sales_date) > 0
THEN ((s.fix_costs/ extract(day FROM (date_trunc('month', sales_date + INTERVAL '1 month') - INTERVAL '1 day'))) *
sales_volume /
NULLIF(SUM(s.sales_volume) FILTER (WHERE s.country != 'NL') OVER (PARTITION BY s.sales_date), 0)
)
/* Divide fixed_cots equaly among countries in case of no sale*/
ELSE (s.fix_costs / extract(day FROM (date_trunc('month', sales_date + INTERVAL '1 month') - INTERVAL '1 day')))
/ SUM(CASE WHEN country <> 'NL' THEN 1 ELSE 0 END) OVER (PARTITION by sales_date)
END) AS imputed_fix_costs
FROM sales s
WHERE country NOT IN ('None')
GROUP BY 1,2,3,4
ORDER BY 1;
此查询适用于DB-Fiddle。
但是,当我在 Amazon Redshift 上运行它时,我收到了 FILTER (WHERE pl.sales_Channel NOT IN ('Marketplace','B2B'))
行的此错误消息。
您知道如何替换/调整这部分查询以使其在 Amazon Redshift 中也能正常工作吗?
【问题讨论】:
Redshift 根本不支持filter()
【参考方案1】:
如果我理解正确,您想为除 NL 以外的所有国家/地区定义每天分摊的固定成本:
select s.*,
(case when country = 'NL' then 0
when sum(sales_volume) over (partition by sales_date) = 0
then (fix_costs / datepart(day, last_day(sales_date))) * 1.0 / sum(case when country <> 'NL' then 1 else 0 end) over (partition by sales_date)
else (fix_costs / datepart(day, last_day(sales_date))) * (sales_volume / sum(case when country <> 'NL' then sales_volume end) over (partition by sales_date))
end) as apportioned_fix_costs
from sales s
where country <> 'None';
注意:您似乎不希望在结果中出现None
,所以它只是被过滤掉了。然后其余的数据似乎都在当月的一个数据上。如果它实际上可以在多个数据上,请在partition by
子句中使用date_trunc()
。
作为参考,Postgres 不支持last_day()
。您可以使用表达式:
select extract(day from date_trunc('month', sales_date) + interval '1 month' - interval '1 day')
DB-Fiddle
【讨论】:
我尝试了您的解决方案,但在 last_day 收到错误消息:dbfiddle.uk/… @Michi 。 . . Postgres 不支持last_day()
。红移可以。在您的数据库中尝试一下。
@Michi 。 . . Redshift 基于 15 年前发布的 Postgres 的古老版本。从那时起,Postgres 发生了很大变化。而且 Redshift 添加了一堆更符合 Oracle 和 SQL Server 的功能。在这一点上,他们正在亲吻堂兄弟而不是兄弟姐妹——甚至可能比“亲吻”更遥远。
@Michi 。 . .代码从第二个条件的总数中删除了 NL,但没有删除第三个条件。我确定了答案。
@Michi 。 . .这就是第二个条件的意图。我修正了错字(省略了over
)子句。 GROUP BY
不是解决这个问题的正确方法。以上是关于将每月固定值拆分为 Redshift 中的天数和国家/地区的主要内容,如果未能解决你的问题,请参考以下文章