我的订单表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.
....
我编写了以下代码,该代码将每小时调用一次以检查是否需要完成插入:
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
。
知道如何编写条件吗?
最佳答案
我并不真正使用 Postgres,我使用 SQL Server,但似乎它们都支持类似的功能集,因此我会将 SQL Server 的操作方式“转换”为 Postgres 语法。我最终可能会遇到一些语法错误。
主要思想
您实际上并不需要显式的
IF
,也不需要在循环中逐一处理各个行。在UPDATE
语句的基于集合的WHERE
条件中执行必要的检查。不要使用
num
列,而是使用last_inserted_datetime
列来保存上次插入的时间戳。最初它将是NULL
。有一个基于集合的
UPDATE
语句,可以在 12 小时内根据需要多次运行,但实际上只有当 12 小时时,它才会更改last_inserted_datetime
几个小时过去了。如果您出于某种原因在超过 24 小时内根本没有运行此语句,它仍然可以,它会以 12 小时为增量进行UPDATE
。因此,如果该过程没有运行(例如 37 小时),只需运行 3 次即可 catch 。使用
RETURNING
子句,在一条语句中对ord
表执行UPDATE
操作,并在A
表中执行INSERT
操作,且仅当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
和 orderdate
之间的差异不到 12 小时,因此不会更新任何行,也不会将任何行插入到 A
中。
等到now
是2015-09-02 06:00:00
,然后运行上面的查询。对于 orderid=12
,now
和 COALESCE(last_inserted_datetime, orderdate)
之间的差异超过 12 小时,因此该行将被更新。
last_inserted_datetime = 2015-09-01 17:23:58.189171 + 12 hrs = 2015-09-02 05:23:58.189171
请注意,last_inserted_datetime
未设置为 now
,而是设置为 orderdate
加 12 小时。
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`.
等到现在
是2015-09-02 18:00:00
,然后运行上面的查询。对于 orderid=12
,now
和 COALESCE(last_inserted_datetime, orderdate)
之间的差异超过 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`.
请注意,last_inserted_datetime
仅增加了 12 小时。再次运行查询,它将一次又一次地递增,直到 catch 当前时间。因此,不会错过任何更新/插入。
关于sql - 如何每12小时执行一次 Action ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32345609/