【问题标题】:Postgres query to get last date value for period along with sum for period?Postgres查询以获取期间的最后日期值以及期间的总和?
【发布时间】:2021-03-29 13:56:46
【问题描述】:

我似乎无法理解如何在单个查询中做一件简单的事情。

我有一个表格,其中包含每天结束时系统中存在的项目余额:

CREATE TEMPORARY TABLE t1 (
    item character varying(10),
    storage_date date,
    qty integer
);

COPY t1 (item, storage_date, qty) FROM stdin;
A       2021-01-01      10
A       2021-01-02      10
A       2021-01-03      10
A       2021-01-04      5
A       2021-01-05      3
B       2021-01-01      1
B       2021-01-02      2
B       2021-01-03      100
B       2021-01-04      50
\.

我需要获取每个期间存储的平均项目数以及期末每个项目的余额。

假设期间在 2021-01-01 和 2021-01-05 之间。

现在,当然,平均值很简单:

SELECT item, sum(qty)/5 FROM t1 GROUP BY item ORDER BY item;
 item | avg
------+-----
 A    |   7
 B    |  30
(2 rows)

但我需要它还包括该期间最后日期 = 2021-01-05 的每个项目的余额(数量)(如您所见,项目 B 也没有该日期的条目,这意味着库存那时是 0。但是如果它是 NULL 或 0 就可以了)。 通缉

 item | avg | balance at end of period
------+-----+---------
 A    |   7 |   3
 B    |  30 |  NULL
(2 rows)

我尝试使用 last_value() 聚合函数:

SELECT item,last_value(qty) OVER (ORDER BY storage_date),sum(qty)/5 from t1 group by 1,2; 

但这显然行不通(我对更高级的 SQL 不熟悉;JOINS、GROUP BY 和 HAVING 是我所理解的)。

我错过了什么?肯定有一些简单的方法而不是编写两个查询?

【问题讨论】:

    标签: sql postgresql group-by aggregate


    【解决方案1】:

    您可以使用子查询:

    SELECT item, sum(qty)/5, balance
    FROM (SELECT t1.*,
                 FIRST_VALUE(qty) OVER (PARTITION BY item ORDER BY storage_date DESCk) as balance
          FROM t1
         ) t1
    GROUP BY item, balance
    ORDER BY item;
    

    您也可以在没有子查询的情况下执行此操作:

    我不确定您为什么使用 SUM(qty) / 5 而不是 AVG(qty),但该逻辑来自您的查询。

    SELECT item, sum(qty)/5,
           (ARRAY_AGG(qty ORDER BY storage_date DESC))[1] as balance
    FROM t1
    GROUP BY item
    ORDER BY item;
    

    【讨论】:

    • 谢谢。带有子查询的解决方案产生 7 行而不是 2 行。 array_agg 似乎工作。我使用 /5 是因为我不确定 PG 将如何处理 NULL 值。它们必须被视为 0,因此如果一个周期是 5 天,如果只有 4 个条目,则平均值是 /5 而不是 /4。
    • @Gnudiff 。 . .那么你的逻辑是正确的。
    • 另外,如果每天都有 条目,那么您的解决方案也很棒。就我而言,当整个周期(5 天)进行时,array_agg 为项目 B 生成第 4 天的余额,因为数据中没有第 5 天的条目。对于 B,它应该为 NULL 或 0。
    【解决方案2】:

    你可以使用左连接

    SELECT ta.*, tb.qty
    FROM(
       SELECT item, sum(qty)/5 
       FROM t1 
       GROUP BY item) ta
    LEFT JOIN  t1 tb ON ta.item = tb.item AND tb.storage_date = TO_DATE('20210105','YYYYMMDD')
    ORDER BY item;
    

    【讨论】:

    • 这似乎工作得很好。我希望避免自我加入,但这可能是最好的。
    猜你喜欢
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多