繁体   English   中英

PostgreSQL for循环中的多个语句

[英]postgresql multiple statements in for loop

我需要编写一个postgressql函数来处理一些时间序列数据,我想遍历每个时间步长并确定是否需要更新未来几个时间步长中的值,并且它将是更新后的值当循环迭代到以下时间步长时,将应用决策。 我希望我已经清楚地解释了。

因此,例如表:

CREATE TEMPORARY TABLE datatable (
                    unixdatetime integer,
                    value        integer,
                );

INSERT INTO datatable (unixdatetime, value) VALUES 
(1,56),
(2,23),
(3,7),
(4,68),
(5,31),
(6,42);

我尝试将以下for循环应用于它:

FOR r IN
     SELECT * FROM datatable
LOOP
   DROP TABLE IF EXISTS currentdata;

   CREATE TEMPORARY TABLE currentdata AS (
        SELECT dt.unixdatetime as currentTime,
               lead(dt.unixdatetime,1) OVER (ORDER BY dt.unixdatetime) AS lead1stTime,
               dt.value AS currentValue,
               lead(dt.value,1) OVER (ORDER BY dt.unixdatetime) AS lead1stVal
        FROM   datatable dt
   );

_counter = 0;

IF (SELECT currentValue%2 FROM currentdata) = 1
   THEN _counter = _counter + 1;
END IF;

IF (SELECT lead1stVal%2 FROM currentdata) = 1
   THEN _counter = _counter + 1;
END IF;

UPDATE datatable dt
SET    value = (CASE WHEN _counter = 2 AND cd.currentValue <> 888 THEN 999
                     ELSE cd.currentValue
               END)
FROM   currentdata cd
WHERE  dt.unixdatetime = cd.currentTime; 

UPDATE datatable dt
SET    value = (CASE WHEN _counter = 2 THEN 888
                     ELSE cd.lead1stVal
               END)
FROM   currentdata cd
WHERE  dt.unixdatetime = cd.lead1stTime;

END LOOP;

我的预期结果将是:

| unixdatetime | Value |
|     1        |   56  |
|     2        |  999  |
|     3        |  888  |
|     4        |   68  |
|     5        |   31  |
|     6        |   42  |

大家都知道,我仍然无法切换到Postgresql思维模式,并且仍然尝试使用python和C ++等在postgressql中不起作用的语言的技巧。 我注意到的是:

  1. 循环中的每个语句都将在整个表上执行,然后再移至循环中的下一条语句。 而是依次执行所有语句,然后再迭代到表的行。

  2. 由于1。,_ counter不能提供与其他语言的for循环相同的效果。 我确实需要for循环中的计数器,因为实际任务需要我提前2个时间步长查看值。

变通办法的任何有用建议,将不胜感激。

提前致谢,

杰森

您可以使用以下语句检索所需的内容,而无需循环。

select unixdatetime, value,
       case  
          when is_odd and next_is_odd then 999 
          when is_odd and prev_is_odd then 888
          else value 
       end as new_value
from (
  select unixdatetime, value, 
         value % 2 <> 0 as is_odd,
         coalesce(lag(value) over (order by unixdatetime) % 2 <> 0, false) as prev_is_odd,
         coalesce(lead(value) over (order by unixdatetime) % 2 <> 0, false) as next_is_odd
  from datatable
) t
order by unixdatetime;

现在,可以用一个语句直接更新整个表:

update datatable
  set value = nv.new_value
from (
  select unixdatetime, value,
         case  
            when is_odd and next_is_odd then 999 
            when is_odd and prev_is_odd then 888
            else value 
         end as new_value
  from (
    select unixdatetime, value, 
           value % 2 <> 0 as is_odd,
           coalesce(lag(value) over (order by unixdatetime) % 2 <> 0, false) as prev_is_odd,
           coalesce(lead(value) over (order by unixdatetime) % 2 <> 0, false) as next_is_odd
    from datatable
  ) t
) nv
where nv.unixdatetime = datatable.unixdatetime
  and nv.new_value <> datatable.value; -- only update those that changed

SQLFiddle示例: http ://sqlfiddle.com/#!15/128d9/1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM