2015-09-02 2 views
2

У меня есть заказы таблицы ord следующим образом:Как выполнить действие каждые 12 часов?

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 и делать вставки в таблицу A каждые 12 часов. Дело в том, что я хочу, чтобы эта вставка была сделана один раз каждые 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 в функции.

любая идея, как написать условие?

ответ

1

Я действительно не использую Postgres, я использую SQL Server, но похоже, что оба они поддерживают подобный набор функций, поэтому я буду «конвертировать», как бы это сделать SQL Server в синтаксис Postgres. Я могу получить некоторые синтаксические ошибки.

Главная идея

  • Вам не нужно явно IF и вам не нужно обрабатывать отдельные строки один за другим в цикле. Проделайте необходимые проверки в заданном WHERE состоянии инструкции UPDATE.

  • Вместо столбца num есть столбец last_inserted_datetime, который будет содержать временную метку последней вставки. Первоначально это будет NULL.

  • У вас есть одно задание UPDATE, которое может выполняться так часто, как вы хотите в течение 12 часов, но оно фактически изменит last_inserted_datetime только в случае прохождения 12 часов. Если вы по какой-то причине не запускаете этот оператор вообще более 24 часов, все равно ОК, он будет UPDATE с 12-часовым шагом. Итак, если процедура не выполнялась, скажем, 37 часов, просто запустите ее три раза, чтобы догнать.

  • Используйте RETURNING положения, чтобы сделать оба UPDATE из ord таблицы и INSERT в A таблицы в одном операторе и только если 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, и запустите запрос выше. Разница между 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, он установлен в 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`. 

Дождитесь 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`. 

Представьте себе планировщик не удалось в течение двух дней и не выполнить запрос до тех пор, пока now2015-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 часов. Запустите запрос еще раз, и он будет увеличиваться снова и снова, пока не наступит текущее время. Таким образом, ни одно из обновлений/вставок не будет пропущено.

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 об управляющих структурах.

+0

mmm, но запрос всегда возвращает значение ... он возвращает коэффициент в часах .. это всегда будет что-то ... – user2641077

Смежные вопросы