Twoja kolumna created_at
to timestamp without time zone
.
Ale now()
zwraca timestamp with time zone
. Wyrażenie now() - '1 hour'::interval
jest zmuszany do timestamp [without time zone]
, co niesie ze sobą dwa problemy :
1.) Nie prosiłeś o to, ale wyrażenie jest niewiarygodne. Jego wynik zależy od aktualnego ustawienia strefy czasowej sesji, w której wykonywane jest zapytanie. Szczegóły tutaj:
Aby wyrażenie było jasne, możesz użyć:
now() AT TIME ZONE 'Europe/London' -- your time zone here
Lub po prostu (przeczytaj instrukcję tutaj) :
LOCALTIMESTAMP -- explicitly take the local time
Rozważę pracę z timestamptz
zamiast tego.
Żadne z nich nie rozwiązuje drugiego problemu:
2.) Odpowiedz na Twoje pytanie. Wykluczenie ograniczeń nie działa. Zgodnie z dokumentacją:
Pogrubiony nacisk na moje.
now()
jest implementacją Postgresa CURRENT_TIMESTAMP
. Jak widać w katalogu systemowym, jest on tylko STABLE
, a nie IMMUTABLE
:
SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';
proname | provolatile
--------+------------
now | s -- meaning: STABLE
Rozwiązania
1.) Możesz obejść to ograniczenie, podając stałą w WHERE
warunek (który jest zawsze "niezmienny"):
select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp; -- derived from your example
2.) Lub „udając” niezmienną funkcję:
CREATE FUNCTION f_now_immutable()
RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC' -- your time zone here
$func$ LANGUAGE sql IMMUTABLE;
A potem:
select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'
Uważaj jednak, jak tego używasz:podczas gdy now()
jest STABLE
(nie zmienia się w czasie trwania transakcji), zmienia się zmieniać między transakcjami, więc uważaj, aby nie używać tego w przygotowanych instrukcjach (z wyjątkiem wartości parametru) lub indeksów lub czegokolwiek, co może cię ugryźć.
3.) Lub możesz dodać pozornie nadmiarową stałą WHERE
klauzule do bieżącego zapytania, które pasują do ograniczenia na Twojej partycji:
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;
Upewnij się tylko, że now() - '1 hour'::interval
wpadnie do właściwej partycji lub oczywiście nie uzyskasz żadnych wyników.
Poza tym:wolałbym użyć tego wyrażenia w CHECK
ograniczenia i zapytanie. Łatwiejszy w obsłudze i robi to samo:
created_at >= '2015-04-01 0:0'::timestamp
AND created_at < '2015-05-01 0:0'::timestamp