使用增量值更新行

时间:2013-06-27 10:18:59

标签: sql postgresql

假设我在postgresql数据库中有一个表,其中包含列:time,speed

现在我添加了一个列“distance”,我希望通过类似的方式插入距离值:

   row[time+1].distance = row[time].distance + row[time+1].speed 

这是更新表格的最快方法吗?

更新

我想尝试类似的事情:

d = 0.0
for row in select time,speed from my_table loop
  d = d + row.speed
  update my_table set distance = d where time = row.time
end loop

这是最好的方法吗?如何让这个代码段运行?

3 个答案:

答案 0 :(得分:1)

所以,我做了一张桌子:

create table whatever ( time_c int4, speed int4, distance int8);

并插入了一些行:

insert into whatever (time_c, speed) select i, random() * 100 from generate_series(1,10) i;

这给了我这个数据:

$ select * from whatever;
 time_c | speed | distance 
--------+-------+----------
      1 |    53 |   [null]
      2 |    17 |   [null]
      3 |    53 |   [null]
      4 |    46 |   [null]
      5 |    31 |   [null]
      6 |    18 |   [null]
      7 |    42 |   [null]
      8 |    15 |   [null]
      9 |     1 |   [null]
     10 |    51 |   [null]
(10 rows)

然后,我使用DO命令:

do $$
DECLARE
    tmp_cur cursor for SELECT * FROM whatever ORDER BY time_c for UPDATE;
    temprec record;
    total_distance INT4 := 0;
BEGIN
    open tmp_cur;
    LOOP
        fetch tmp_cur INTO temprec;
        EXIT WHEN NOT FOUND;
        total_distance := total_distance + temprec.speed;
        UPDATE whatever SET distance = total_distance WHERE CURRENT OF tmp_cur;
    END LOOP;
END;
$$;

这就是全部:

$ select * from whatever;
 time_c | speed | distance 
--------+-------+----------
      1 |    53 |       53
      2 |    17 |       70
      3 |    53 |      123
      4 |    46 |      169
      5 |    31 |      200
      6 |    18 |      218
      7 |    42 |      260
      8 |    15 |      275
      9 |     1 |      276
     10 |    51 |      327
(10 rows)

答案 1 :(得分:1)

无需循环甚至无需存储此数据。显然你想要一个“速度”列的“运行总和”,可以使用窗口函数轻松完成:

(从Depesz的回答中无耻地窃取样本数据)

create table whatever 
( 
   time_c int4, 
   speed int4, 
   distance int8
);

insert into whatever (time_c, speed)
values
( 1,53), 
( 2,17), 
( 3,53), 
( 4,46), 
( 5,31), 
( 6,18), 
( 7,42), 
( 8,15), 
( 9, 1), 
(10,51);

select time_c, 
       speed,
       sum(speed) over (order by time_c) as distance
from whatever 
order by time_c;
time_c | speed | distance
-------+-------+---------
1      | 53    | 53      
2      | 17    | 70      
3      | 53    | 123     
4      | 46    | 169     
5      | 31    | 200     
6      | 18    | 218     
7      | 42    | 260     
8      | 15    | 275     
9      | 1     | 276     
10     | 51    | 327     

如果您确实想要存储可以轻松计算的数据,可以使用单个更新语句来执行此操作:

with derived_data as ( 
  select time_c, 
         speed,
         sum(speed) over (order by time_c) as distance
  from whatever 
)
update whatever 
  set distance = dd.distance
from derived_data dd
where dd.time_c = whatever.time_c;

此更新假定time_c是表中的唯一属性。

SQLFiddle示例:http://sqlfiddle.com/#!12/16332/2

答案 2 :(得分:0)

看到你的评论,最简单的方法是将row.distance表示为前一行的速度之和*。

选择看起来像这样(使用它来运行一些检查):

select t1.id, sum (t1.speed * time_diff) as distance
from table t1 join table t2 on t1.time >= t2.time
group by t1.id

如果您对此感到满意,请将其用作更新声明中的子选择:

update table ... from (...) sub where sub.id = table.id

(旁白:请注意,您的距离公式不考虑加速度。)