簡體   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