带有“lag()”窗口函数的 PostgreSQL 更新查询

Posted

技术标签:

【中文标题】带有“lag()”窗口函数的 PostgreSQL 更新查询【英文标题】:PostgreSQL update query with "lag()" window function 【发布时间】:2018-02-28 18:52:20 【问题描述】:

我有一个涉及 Postgresql 数据库的任务。我对 SQL 不是很熟悉。

我有一张交易产品每周营业额的表格。

每周提供以下信息:产品、周数、周营业额(可能是正数或负数,取决于天气,购买或出售了更多产品)。我添加了一个列,其中包含每周的期末余额。我在表中有第一周所有产品的期末余额(week_number = 0),但对于所有其他周为“null”。下面提供了一些示例性记录。

    product                     | week_number | turnover | closing_balace
--------------------------------+-------------+----------+----------------
 BLGWK-05.00*1250*KR-S235JRN0-A |           0 |    50.00 |    1240.00
 BLGWK-05.00*1250*KR-S355J2CN-K |           0 |    45.70 |     455.75
 BLGWK-05.00*1464*KR-DD11NIET-K |           0 |    30.01 |     300.00
 BLGWK-05.00*1500*KR-DD11NIET-R |           1 |    10.22 |
 BLGWK-05.00*1500*KR-S235J2CU-K |           1 |    88.00 |

我需要一个查询来使用以下计算填充所有“空”close_balance:

closing_balance = closing_balance of the same product for previous week + turnover for the week.

我试过这个查询:

update table_turnover 
set closing_balance = (select lag(closing_balance, 1) over (partition by product order by week_number) + turnover) 
where week_number > 0;

它从来没有工作过 - “第 0 周”以上的关闭余额的“空”值仍然是“空”。

我也试过了:

update table_turnover 
set closing_balance = (select 
                           case when week_number = 0 
                                   then closing_balance
                                   else (lag(closing_balance, 1) over (partition by product order by week_number) + turnover)
                           end
                       from table_turnover)

这会产生错误

子查询返回多条记录作为表达式

知道如何进行此计算吗?

提前谢谢你。

【问题讨论】:

【参考方案1】:

from 子句中使用子查询:

update table_turnover 
    set closing_balance = (ttprev.prev_closing_balance + ttprev.turnover) 
    from (select tt.*,
                 lag(closing_balance) over (partition by product order by 
week_number) as prev_closing_balance
          from table_turnover tt
         ) ttprev
    where ttprev.product = tt.product and ttprev.week_number = tt.week_number and
          week_number > 0;

或者,如果您想在select 中使用子查询:

update table_turnover 
    set closing_balance = (turnover +
                           (select tt2.closing_balance 
                            from table_turnover tt2
                            where tt2.product = tt.product and tt2.week_number = tt.week_number - 1
                           )
                          )
    where week_number > 0;

为了提高性能(在任一版本上),您需要在table_turnover(product, week_number, closing_balance) 上建立索引。

【讨论】:

感谢您的回答。不幸的是,我无法运行查询。它给出了一个错误:“第 3 行中的表 tt 没有 FROM 子句”。知道为什么会这样吗? 好的。我进行了查询,谢谢。不幸的是,它们非常缓慢(执行所有产品需要 DAYS 天)。还有其他想法吗? @Broono 。 . .桌子有多大?无论如何,索引应该可以解决问题。 为什么UPDATEs 按正确的顺序处理行?例如,如果它在第 2 周尚未填满时尝试更新第 3 周,我们将在第 3 周得到NULLsPostgreSQL 由于其版本控制系统和查询计划,不保证表中的任何顺序。 @EvgenyNozdrev 。 . .如果您有问题,请作为问题提出。

以上是关于带有“lag()”窗口函数的 PostgreSQL 更新查询的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery 中的 CONDITIONAL_TRUE_EVENT 的替代方案,带有 LAG() 函数?

带有 LIMIT 的 PostgreSQL 窗口函数

pyspark 是不是支持窗口函数(例如 first、last、lag、lead)?

Alter Table 中的 LAG 函数产生窗口函数错误

如何为不同的观察组使用 LAG 和 LEAD 窗口函数

在 MonetDB 中最快实现lead() 或 lag() 窗口函数