Вашата колона created_at
е timestamp without time zone
.
Но now()
връща timestamp with time zone
. Изразът now() - '1 hour'::interval
е принуден към timestamp [without time zone]
, което носидва проблема :
1.) Не сте поискали това, но изразът е ненадежден. Резултатът зависи от текущата настройка на часовата зона на сесията, в която се изпълнява заявката. Подробности тук:
За да направите израза ясен, можете да използвате:
now() AT TIME ZONE 'Europe/London' -- your time zone here
Или просто (прочетете ръководството тук) :
LOCALTIMESTAMP -- explicitly take the local time
Бих обмислил работа с timestamptz
вместо това.
Нито едно от двете не решава втория ви проблем:
2.) Отговор на вашия въпрос. Изключването на ограничение не работи. Съгласно документацията:
Удебелен акцент е мой.
now()
е изпълнението на Postgres на CURRENT_TIMESTAMP
. Както можете да видите в системния каталог, той е само STABLE
, а не IMMUTABLE
:
SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';
proname | provolatile
--------+------------
now | s -- meaning: STABLE
Решения
1.) Можете да преодолеете ограничението, като предоставите константа в WHERE
условие (което винаги е „неизменно“):
select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp; -- derived from your example
2.) Или чрез „фалшифициране“ на неизменна функция:
CREATE FUNCTION f_now_immutable()
RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC' -- your time zone here
$func$ LANGUAGE sql IMMUTABLE;
И след това:
select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'
Все пак внимавайте как използвате това:докато now()
е STABLE
(не се променя по време на транзакцията), той се променя промяна между транзакциите, така че внимавайте да не използвате това в подготвени отчети (освен като стойност на параметър) или индекси или нещо друго, където може да ви ухапе.
3.) Или можете да добавите привидно излишна константа WHERE
клаузи към текущата ви заявка, които съответстват на ограничението на вашия дял:
SELECT count(*)
FROM events
WHERE created_at > now() - '1 hour'::interval
AND created_at >= '2015-04-01 00:00:00'::timestamp
AND created_at <= '2015-04-30 23:59:59.999999'::timestamp;
Просто се уверете, че now() - '1 hour'::interval
попада в правилния дял или очевидно няма да получите резултати.
Настрана:предпочитам да използвам този израз в CHECK
ограничения и заявка. По-лесен за работа и прави същото:
created_at >= '2015-04-01 0:0'::timestamp
AND created_at < '2015-05-01 0:0'::timestamp