Váš sloupec created_at
je timestamp without time zone
.
Ale now()
vrátí timestamp with time zone
. Výraz now() - '1 hour'::interval
je vynucováno timestamp [without time zone]
, která s sebou nese dva problémy :
1.) Na tohle jste se neptal, ale ten výraz je nespolehlivý. Jeho výsledek závisí na aktuálním nastavení časového pásma relace, ve které se dotaz provádí. Podrobnosti zde:
Aby byl výraz jasný, můžete použít:
now() AT TIME ZONE 'Europe/London' -- your time zone here
Nebo jen (přečtěte si manuál zde) :
LOCALTIMESTAMP -- explicitly take the local time
Zvažoval bych práci s timestamptz
místo toho.
Ani jedno nevyřeší váš druhý problém:
2.) Odpověď na vaši otázku. Vyloučení omezení nefunguje. Podle dokumentace:
Odvážný důraz můj.
now()
je implementace Postgres CURRENT_TIMESTAMP
. Jak můžete vidět v katalogu systému, je pouze STABLE
, nikoli IMMUTABLE
:
SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';
proname | provolatile
--------+------------
now | s -- meaning: STABLE
Řešení
1.) Omezení můžete překonat poskytnutím konstanty v WHERE
podmínka (která je vždy "neměnná"):
select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp; -- derived from your example
2.) Nebo „předstíráním“ neměnné funkce:
CREATE FUNCTION f_now_immutable()
RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC' -- your time zone here
$func$ LANGUAGE sql IMMUTABLE;
A pak:
select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'
Buďte opatrní, jak to používáte:zatímco now()
je STABLE
(nemění se po dobu trvání transakce), mění změny mezi transakcemi, takže dávejte pozor, abyste to nepoužili v připravených příkazech (kromě hodnoty parametru) nebo indexech nebo v čemkoli, kde by vás to mohlo kousnout.
3.) Nebo můžete přidat zdánlivě nadbytečnou konstantu WHERE
klauzule k vašemu aktuálnímu dotazu, které odpovídají omezení na vašem oddílu:
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;
Jen se ujistěte, že now() - '1 hour'::interval
spadne do správného oddílu nebo samozřejmě nezískáte žádné výsledky.
Stranou:Tento výraz bych raději použil v CHECK
omezení a dotaz. Snáze se ovládá a dělá to samé:
created_at >= '2015-04-01 0:0'::timestamp
AND created_at < '2015-05-01 0:0'::timestamp