1

假设我在 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

这是最好的方法吗?我怎样才能让这个片段运行?

4

3 回答 3

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)
于 2013-06-27T11:00:55.200 回答
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;
时间_c | 速度 | 距离
--------+-------+---------
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

于 2013-06-27T13:18:59.097 回答
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

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

于 2013-06-27T10:36:11.943 回答