如何每12小时执行一次动作?

时间:2015-09-02 05:58:17

标签: sql postgresql

我的订单表ord如下:

orderid orderstatus orderdate                          num
12         2         2015-09-01 17:23:58.189171         0
13         1         2015-09-01 17:25:12.237141         0

我需要编写一个函数来获取orderstatus = 2中的所有订单,并且每12小时插入一次表A。问题是我希望这个插入每12个小时完成一次...... num表示我插入到表A的次数。

基本上应该有这个逻辑:

time passed < 12     num = 0  OK.
12<time passed<24    num = 0  do insert to table A.  num = 1 OK.
24 time passed<36    num = 1  do insert to table A.  num = 2 OK.
.... 

我编写了以下代码,每小时调用一次代码来检查是否需要执行insert:

CREATE OR REPLACE FUNCTION func()
  RETURNS void AS
$BODY$
declare
    ROW record;
    v_time int;
begin   
for row in 
    Select  orderid,orderdate,num
    From ord
    where orderstatus=2
loop 

    SELECT (extract(epoch from localtimestamp - ROW.orderdate::timestamp)/3600)::integer into v_time;

     if.........
         insert into A
         update ord set num = num+1 where orderid=ROW.orderid

end loop;
return;   
end;
$BODY$
  LANGUAGE plpgsql VOLATILE

问题是我不知道如何在函数中编写if

任何想法如何写条件?

2 个答案:

答案 0 :(得分:1)

我没有真正使用Postgres,我使用SQL Server,但似乎它们都支持类似的功能集,因此我将“转换”我如何将SQL Server转换为Postgres语法。我可能最终会遇到一些语法错误。

主要想法

  • 您不需要显式IF,也不需要在循环中逐个处理单个行。在WHERE语句的基于集合的UPDATE条件中进行必要的检查。

  • 而不是num列的列last_inserted_datetime将保留最后一次插入的时间戳。最初它将是NULL

  • 有一个基于集合的UPDATE语句,可以在12小时内按需运行,但只有在12小时后才会实际更改last_inserted_datetime。如果由于某种原因,完全不运行此语句超过24小时仍然可以,它将以12小时为增量UPDATE。因此,如果程序没有运行,比如37小时,只需运行三次即可赶上。

  • 使用RETURNING子句在UPDATE表和ordINSERT同时在一个语句中执行A表,并且仅在{{1}实际上改变了任何行。目前尚不清楚您在UPDATE中插入的确切内容。根据需要调整以下查询。

将此查询放入存储过程并安排定期运行(例如,每小时或更长时间运行一次)。

A

让我们看看它是如何运作的。我们从这个WITH CTE AS ( UPDATE ord SET last_inserted_datetime = COALESCE(last_inserted_datetime, orderdate) + interval '12 hours' WHERE orderstatus = 2 AND (now() - COALESCE(last_inserted_datetime, orderdate)) > interval '12 hours' RETURNING orderid, orderdate, last_inserted_datetime ) INSERT INTO A (orderid, orderdate, last_inserted_datetime) SELECT orderid, orderdate, last_inserted_datetime FROM CTE ; 表开始:

ord

orderid orderstatus orderdate last_inserted_datetime 12 2 2015-09-01 17:23:58.189171 NULL 13 1 2015-09-01 17:25:12.237141 NULL 成为now,然后我们运行上面的查询。 2015-09-01 18:00:00now之间的差异小于12小时,因此不会更新任何行,也不会将任何行插入orderdate

等到Anow,然后运行上面的查询。对于2015-09-02 06:00:00nowCOALESCE(last_inserted_datetime, orderdate)之间的差异超过12小时,因此此行会更新。

orderid=12

请注意,last_inserted_datetime = 2015-09-01 17:23:58.189171 + 12 hrs = 2015-09-02 05:23:58.189171 未设置为last_inserted_datetime,设置为now加12小时。

orderdate表变为:

ord

等到orderid orderstatus orderdate last_inserted_datetime 12 2 2015-09-01 17:23:58.189171 2015-09-02 05:23:58.189171 13 1 2015-09-01 17:25:12.237141 NULL Plus one row is inserted into `A`. now,然后运行上面的查询。对于2015-09-02 18:00:00nowCOALESCE(last_inserted_datetime, orderdate)之间的差异超过12小时,因此此行会更新。

orderid=12表变为:

ord

想象一下,调度程序失败了两天,直到orderid orderstatus orderdate last_inserted_datetime 12 2 2015-09-01 17:23:58.189171 2015-09-02 17:23:58.189171 13 1 2015-09-01 17:25:12.237141 NULL Plus one row is inserted into `A`. now才执行查询。

2015-09-04 18:00:00表变为:

ord

请注意,orderid orderstatus orderdate last_inserted_datetime 12 2 2015-09-01 17:23:58.189171 2015-09-03 05:23:58.189171 13 1 2015-09-01 17:25:12.237141 NULL Plus one row is inserted into `A`. 仅增加了12小时。再次运行查询,它将一次又一次递增,直到它赶上当前时间。因此,不会错过任何更新/插入。

答案 1 :(得分:0)

我假设你可以写一些类似的东西:

...
SELECT (extract(epoch from localtimestamp - ROW.orderdate::timestamp)/3600)::integer into v_time;
IF FOUND THEN
   -- begin code from your last code snippet
   insert into A 
   update ord set num = num+1 where orderid=ROW.orderid
   -- end 
ELSE
   ...
END IF;
... 

您可以查看Postgres documentation有关控制结构的详细信息。