Select 并在 Postgres 数据库中使用条件计算进行更新

Select and update with conditional calculations in a Postgres database

我有一个名为 rain_tanks 的 Postgres table,如下所示:

 id   hour     rain    demand    current_volume  unmet_demand
 1    00:00    4.0     2.0       2               0.0
 2    00:10    3.0     4.0       [null]          [null]
 3    00:20    1.0     6.0       [null]          [null]
 4    00:30    7.0     3.0       [null]          [null]

我想做这个计算并更新 current_volume 和 unmet_demand 列(这段代码只是为了展示需要做什么。我想在不使用函数或代码的情况下完成Python 中的行):

a = lag(current_volume) + rain - demand
if a < 0: 
    unmet_demand = current_volume    
    current_volume = 0
else:
    unmet_demand = 0
    current_volume = a

预期 table:

 id   hour     rain    demand    current_volume  unmet_demand
 1    00:00    4.0     2.0       2               0
 2    00:10    3.0     4.0       1               0
 3    00:20    1.0     6.0       0               -4
 4    00:30    7.0     3.0       4               0

我想我需要的是首先 SELECT 然后更新列。我为 SELECT 尝试了以下方法,但它不起作用:

import psycopg2 as p
conn = p.connect("dbname = 'test' user = 'postgres' password = 'pass' host = 'localhost'")
cur = conn.cursor()

cur.execute("""SELECT Id,rain,demand,current_volume,unmet_demand, 
                      CASE WHEN (rain - demand + lag(current_volume) over(
                                 order by Id)) >= 0 
                           THEN (rain - demand + lag(current_volume) over(
                                 order by Id)) ELSE 0 END 
               FROM rain_tanks ORDER BY Id""")

编辑

这是一个与性能相关的附加问题。我决定在 Postgres 数据库中进行这些计算的原因是想看看与在 Python 中使用 Numpy 数组相比是否有速度提升。我有大约 1000 万点用于降雨和需求列,这里提供的答案比 Numpy 降雨和需求数组的等效 python 函数花费的时间更长。还有space提高查询性能吗?

您应该使用递归 cte 来获得所需的结果。由于每一行都取决于之前的计算,因此 lag.

无法实现
WITH RECURSIVE CTE(id,rain,demand,new_current_volume,new_unmet_demand) as 
(SELECT Id,rain,demand
 ,case when rain-demand <0 then 0 else rain-demand end as new_current_volume
 ,case when rain-demand <0 then rain-demand else 0 end as new_unmet_demand
 FROM rain_tanks
 WHERE id = 1
 UNION ALL
 SELECT r2.Id,r2.rain,r2.demand
 ,case when r1.new_current_volume+r2.rain-r2.demand <0 then 0 else r1.new_current_volume+r2.rain-r2.demand end
 ,case when r1.new_current_volume+r2.rain-r2.demand <0 then r1.new_current_volume+r2.rain-r2.demand else 0 end
 FROM cte r1
 JOIN rain_tanks r2 ON r2.id=r1.id+1
)
SELECT * FROM CTE;

Sample Demo

编辑:

update table 基于新计算的值,包括 2 null 列,列名来自 table,以及计算的列。然后你可以 update 他们在 cte 之后进行这些计算。

WITH RECURSIVE CTE(id,rain,demand,current_volume,unmet_demand,new_current_volume,new_unmet_demand) as 
(SELECT Id,rain,demand,null,null
 ,case when rain-demand <0 then 0 else rain-demand end as new_current_volume
 ,case when rain-demand <0 then rain-demand else 0 end as new_unmet_demand
 FROM rain_tanks
 WHERE id = 1
 UNION ALL
 SELECT r2.Id,r2.rain,r2.demand,null,null
 ,case when r1.new_current_volume+r2.rain-r2.demand <0 then 0 else r1.new_current_volume+r2.rain-r2.demand end
 ,case when r1.new_current_volume+r2.rain-r2.demand <0 then r1.new_current_volume+r2.rain-r2.demand else 0 end
 FROM cte r1
 JOIN rain_tanks r2 ON r2.id=r1.id+1
)
UPDATE rain_tanks r
SET current_volume=c.new_current_volume
   ,unmet_demand=c.new_unmet_demand
FROM cte c
WHERE r.id=c.id;