Din kolonne created_at
er timestamp without time zone
.
Men now()
returnerer timestamp with time zone
. Udtrykket now() - '1 hour'::interval
bliver tvunget til at timestamp [without time zone]
, som rummer to problemer :
1.) Du bad ikke om denne, men udtrykket er upålideligt. Resultatet afhænger af den aktuelle tidszoneindstilling for den session, som forespørgslen udføres i. Detaljer her:
For at gøre udtrykket tydeligt kan du bruge:
now() AT TIME ZONE 'Europe/London' -- your time zone here
Eller bare (læs manualen her) :
LOCALTIMESTAMP -- explicitly take the local time
Jeg ville overveje at arbejde med timestamptz
i stedet.
Ingen af delene løser dit andet problem:
2.) Svar på dit spørgsmål. Udelukkelse af begrænsninger virker ikke. Pr. dokumentation:
Fed fremhævelse mine.
now()
er Postgres-implementeringen af CURRENT_TIMESTAMP
. Som du kan se i systemkataloget, er det kun STABLE
, ikke IMMUTABLE
:
SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';
proname | provolatile
--------+------------
now | s -- meaning: STABLE
Løsninger
1.) Du kan overvinde begrænsningen ved at angive en konstant i WHERE
betingelse (som altid er "uforanderlig"):
select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp; -- derived from your example
2.) Eller ved at "falske" en uforanderlig funktion:
CREATE FUNCTION f_now_immutable()
RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC' -- your time zone here
$func$ LANGUAGE sql IMMUTABLE;
Og så:
select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'
Vær dog forsigtig med, hvordan du bruger dette:while now()
er STABLE
(ændres ikke i en transaktions varighed), gør det det skift mellem transaktioner, så pas på ikke at bruge dette i forberedte udsagn (undtagen som parameterværdi) eller indekser eller andet, hvor det kan bide dig.
3.) Eller du kan tilføje en tilsyneladende redundant konstant WHERE
klausuler til din aktuelle forespørgsel, der matcher begrænsningen på din partition:
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;
Bare sørg for, at now() - '1 hour'::interval
falder ind i den rigtige partition, eller du får ingen resultater, naturligvis.
Til side:Jeg vil hellere bruge dette udtryk i CHECK
begrænsninger og forespørgsel. Lettere at håndtere og gør det samme:
created_at >= '2015-04-01 0:0'::timestamp
AND created_at < '2015-05-01 0:0'::timestamp