ruby-on-rails - postgresql 计算每个年龄组的库存数量
问题描述
我想计算表中股票的年龄<30 days
,并按年龄30 days to 60 days exclusive
、、、60 days to 90 days exclusive
和对它们进行分组。这是我的库存示例表:90 days to 6 months exclusive
> 6 months
<id:1, item_id:1, adjustment: 5, amount:5, date:"2020-01-01T00:00:00-04:00">
<id:2, item_id:1, adjustment: 1, amount:6, date:"2020-01-01T10:00:00-04:00">
<id:3, item_id:2, adjustment: 10, amount:10, date:"2020-01-01T00:00:00-04:00">
<id:4, item_id:1, adjustment: 5, amount:11, date:"2020-02-01T00:00:00-04:00">
<id:5, item_id:1, adjustment: -1, amount:10, date:"2020-03-02T00:00:00-04:00">
<id:6, item_id:2, adjustment: 1, amount:11, date:"2020-03-02T00:00:00-04:00">
查询将被赋予一个日期参数,日期将应用于该参数。因此,在这种情况下,假设日期参数是2020-03-02T00:00:00
,如果我们查看 <30 天,这将意味着 2020-03-02T00:00:00 之前的 30 天。这里要注意的重要一点:每当调整小于 0 时,就意味着一件商品已售出,并且该库存已从最旧的库存中删除。此外,对于每个日期类别,您都需要获取最新的 item_id,因为这将代表该项目的最新库存。更清楚地说,查询上表的示例响应是:
result = {
"<30 days": 1,
"30 days to 60 days exclusive": 5,
"60 days to 90 days exclusive": 15,
"90 days to 6 months exclusive": 0,
"> 6 months": 0
}
请允许我解释一下结果:
- 少于 30 天的库存量取自
id:6
(表中最后一条记录)的量。这个非常简单,它是在 3 月初添加一个额外项目的结果。 - 30 到 60 天的库存数量是在 2020-02-01T00:00:00 (id: 4, item_id: 1) 添加的数量。此数量为 5,因为这是该日期添加的数量。此值不包括 2020 年 1 月 1 日的项目,因为这些项目正好有 60 天的历史。
- 60 至 90 天的库存量是 2020-01-01 增加的库存量。重要提示:所以这需要从那时起每个 item_id 的最新记录(因此对于 item_id:1 它将是:
id:2
而对于 item_id:2 它将是id:3
)。此外,item_id:1
我们可以看到,在记录中id:5
,一个项目被删除了,因为我们假设它是最旧的库存,它将从那批项目中删除。因此,这个值是通过 6(id:2) + 10(id:3) - 1(id:5) = 25 来计算的。
这里需要注意的重要一点是,当调整为负数时(意味着一个项目被移除/出售),我们将假设它是最旧的被移除的项目,这就是为什么我们没有从我们之前减去 1 个移除的id:4
项目计算 30 至 60 天(不含)的库存。
所以我正在尝试编写一个 sql 查询并使用Model.find_by_sql
. 任何帮助将不胜感激。为了测试目的,我在这里创建了小提琴表。谢谢。
解决方案
这可能是一个带有硬编码日期的解决方案'2020-03-02T00:00:00'
。
但需要用一些对冲案例来检验,主要是负调整。
例如,如果调整日期2020-03-02T00:00:00-04:00
而不是-1
它-7
,当然是针对不同的输入日期。
最难处理的情况是当您对 a 进行负调整而item_id
对另一个 进行正调整时item_id
。
我不确定这些情况下的行为可能是什么。因此,不仅仅是一个完美的工作解决方案,还可以将其视为一个起点,一个粗略的草图。
SELECT
SUM (
CASE
WHEN grouped_item.difference < interval '30 days' and grouped_item.difference >= interval '0 days' THEN
grouped_item.sum
ELSE
0
END
) AS "<30 days",
SUM (
CASE
WHEN grouped_item.difference >= interval '30 days' and grouped_item.difference < interval '60 days' THEN
grouped_item.sum
ELSE
0
END
) AS "30 days to 60 days exclusive",
SUM (
CASE
WHEN grouped_item.difference >= interval '60 days' and grouped_item.difference < interval '90 days' THEN
grouped_item.sum
ELSE
0
END
) AS "60 days to 90 days exclusive",
SUM (
CASE
WHEN grouped_item.difference >= interval '90 days' and grouped_item.difference < interval '6 month' THEN
grouped_item.sum
ELSE
0
END
) AS "90 days to 6 months exclusive",
SUM (
CASE
WHEN grouped_item.difference >= interval '6 month' THEN
grouped_item.sum
ELSE
0
END
) AS "> 6 months"
FROM
(
select inventory.item_id, sum(inventory.adjustment),
case
when inventory.adjustment >= 0 then
'2020-03-02T00:00:00'::timestamp - inventory.date::timestamp
else (
select '2020-03-02T00:00:00'::timestamp - min(I.date::timestamp)
from inventory I
where I.item_id = inventory.item_id
)
end difference
from inventory
where inventory.date::timestamp <= '2020-03-02T00:00:00'::timestamp
group by inventory.item_id, difference
) as grouped_item;
/*
<30 days | 30 days to 60 days exclusive | 60 days to 90 days exclusive | 90 days to 6 months exclusive | > 6 months
----------+------------------------------+------------------------------+-------------------------------+------------
1 | 5 | 15 | 0 | 0
*/
推荐阅读
- javascript - JavaScript 在 Ruby on Rails 应用程序中不起作用
- apache-spark - 从 pyspark 中的现有数据框创建多个数据框
- unity3d - 如何让应用内购买项目在 Google Play 上显示给播放器
- rest - 403 Forbidden SQL-Injection Error for POST with Content-Type = text/xml
- heroku - 需要 Heroku Redis 升级吗?
- python - python上的霍夫变换问题
- reactjs - 我部署的站点看起来与本地版本不同
- flutter - 如何在颤动中使用 navigatorKey 传递值下一个屏幕?
- node.js - 使用附加调试 Typescript Node 应用程序
- javascript - 将 Array 中的字符串转换为数字,然后将它们全部相加以获得 JavaScript 中的总数