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;
编辑:
到 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;
我有一个名为 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;
编辑:
到 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;