我的订单表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
。
任何想法如何写条件?
答案 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
表和ord
中INSERT
同时在一个语句中执行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:00
和now
之间的差异小于12小时,因此不会更新任何行,也不会将任何行插入orderdate
。
等到A
为now
,然后运行上面的查询。对于2015-09-02 06:00:00
,now
和COALESCE(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:00
,now
和COALESCE(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有关控制结构的详细信息。