ruby-on-rails - Postgresql 使用原始 sql 填充缺失的日期

标签 ruby-on-rails postgresql date join select

我有下表(简化如下):

订单:

<id: 1, shipping: 6.0, price: 20.0>
<id: 2, shipping: 10.0, price: 30.0>
<id: 3, shipping: 7.0, price: 12.0>
<id: 4, shipping: 5.0, price: 0.0> #0 dollars because it was updated after return

销售:

<id: 1, order_id: 1, price:10.0, qty:2, date: "2020-06-01T01:16:15-04:00">
<id: 2, order_id: 1, price:9.0, qty: 1, date: "2020-06-01T01:16:15-04:00">
<id: 3, order_id: 2, price:15.0, qty:2, date: "2020-06-01T01:23:53-04:00">
<id: 4, order_id: 3, price:4.0, qty: 1, date: "2020-06-01T20:28:18-04:00">
<id: 5, order_id: 3, price:4.0, qty: 2, date: "2020-06-01T20:31:15-04:00">
<id: 6, order_id: 4, price:29.0, qty:1, date: "2020-06-03T20:16:15-04:00">

退款:

<id: 1, order_id: 1, qty:1, amount: 9.0, date: "2020-06-01T01:23:15-04:00">
<id: 2, order_id: 4, qty:1, amount: 29.0, date: "2020-06-04T03:34:53-04:00">

我正在编写原始sql来计算运费(即sum(orders.shipping))、总订单(即COUNT(DISTINCTorders.id))和净销售额(即 sales.price * sales.qty - COALESCE(refunds.refund_amount, 0))按天分组。搜索将采用格式为 YYYY-MM-DDThh24:mi:ssmin_datemax_date 来过滤销售或退款不在日期范围内。我遇到的问题是使用 generate_series 添加表中不存在的所有日期,并将值全部设置为 0。因此,如果 min_date = 2020-06-01T00,则为示例响应:00:00 和 max_date = 2020-06-05T23:59:59 类似于:

"2020-06-01": {shipping: 6, total_orders: 3, net_sales: 62.0},
"2020-06-02": {shipping: 0, total_orders: 0, net_sales: 0}, --> newly added
"2020-06-03": {shipping: 5, total_orders: 1, net_sales: 29},
"2020-06-04": {shipping: 0, total_orders: 1, net_sales: -29.0},
"2020-06-05": {shipping: 0, total_orders: 0, net_sales: 0} --> newly added.

谁能帮我得到上面想要的结果。我看过一些例子,但我无法让它适合我的场景。谢谢!

最佳答案

我认为这会做你想要的:

select 
    d.dt, 
    o.shipping,
    s.total_orders,
    coalesce(s.sales_amount, 0) - coalesce(r.refound_amount, 0) net_sales
from generate_series(?::timestamp, ?::timestamp, interval '1 day') d(dt)
left join lateral (
    select 
        count(distinct order_id) total_orders,
        sum(price * quantity) sales_amount,
        array_agg(order_id) order_ids
    from sales s
    where s.date >= d.dt and s.date < d.dt + interval '1 day'
) s on true
left join lateral (
    select sum(o.shipping) shipping
    from orders o
    where o.id = any(s.order_ids)
) o on true
left join lateral (
    select sum(r.amount) refound_amount
    from refunds r
    where r.order_id = any(s.order_ids)
) r on true

查询首先生成给定间隔内的所有日期(? 代表两个日期参数)。

然后,我们使用带有聚合查询的横向联接来获取该期间内发生的所有销售的信息。另一个稍后加入带来与第一个横向加入选择的order_id相对应的运费,另一个带来相应的退款。

关于ruby-on-rails - Postgresql 使用原始 sql 填充缺失的日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62489496/

相关文章:

ruby-on-rails - Rails 3.0.4 中没有路由匹配

python - Google App Engine Flexi 上 Django 的 Postgres 设置

date - 考虑另一个 TZ 作为引用的服务器时间

java - 在Java中设置文件创建时间戳

javascript - 在表单提交js上重新格式化引导日期选择器

mysql - 通过 Rails 将 SQL 文件或 Excel 文件中的数据导入数据库

ruby-on-rails - 如何将 CSS 与 ruby​​ on rails 应用程序一起使用?

ruby-on-rails - 用户电子邮件的 Rails 验证 - 只希望它在用户注册或更新电子邮件地址时进行验证

postgresql - Cloud SQL (postgres) 外部数据包装器连接超时到副本实例

node.js - PostgreSQL node.js 准备语句最大绑定(bind)