2017-04-26 24 views
0

我有一個名爲rain_tanks一個Postgres表更新,如下圖所示:選擇並在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 

我想我需要的是先選擇和更新列。我嘗試了以下的選擇,但它不工作:

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

所以你有第一行這些值..並希望得到它的其他人? –

回答

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; 
+0

你是對的,我並不期待這個!它的工作完美。 –

+0

只是一個簡單的問題。保存結果的最佳方法是什麼(最好在同一張表中)? –

+0

你的意思是更新表? –