2017-04-26 22 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 

私が必要と思うのは、最初に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""") 

すべてのヘルプは本当にいただければ幸いです。

EDIT(パフォーマンスに関する質問を追加):Postgresデータベースでこれらの計算を行う理由は、Pythonでnumpy配列を使用するのと比較してスピードが向上しているかどうかを確認することでした。私は雨と需要の列のための約1000万点を持っており、ここで提供される答えは、雨と需要のnumpy配列以上の同等の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

EDIT:新たに計算された値に基づいて

updateには、表計算のものと一緒にテーブルの列名と2つのnull列を含みます。次に、あなたは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; 
+0

あなたはそうです、私はこれを期待していませんでした!その完璧に動作します。 –

+0

ただの簡単な質問です。結果を保存する最良の方法は何ですか(できれば同じ表にあります)。 –

+0

あなたはテーブルを更新することを意味しますか? –