Я действительно не использую 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`.
Представьте себе планировщик не удалось в течение двух дней и не выполнить запрос до тех пор, пока 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 часов. Запустите запрос еще раз, и он будет увеличиваться снова и снова, пока не наступит текущее время. Таким образом, ни одно из обновлений/вставок не будет пропущено.
mmm, но запрос всегда возвращает значение ... он возвращает коэффициент в часах .. это всегда будет что-то ... – user2641077