在postgres数据库

时间:2017-04-26 23:40:51

标签: python sql database select psycopg2

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

 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

预期表格:

 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和UPDATE列。我为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万点的雨和需求列,这里提供的答案需要比同等数量的python函数更长的时间比雨量和需求量大。还有空间来提高查询的性能吗?

1 个答案:

答案 0 :(得分:0)

您应该使用递归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表格添加2个null列,其中包含表格中的列名称以及计算出的列数。然后,您可以在cte。

之后使用这些计算update
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;