Votre colonne created_at
est timestamp without time zone
.
Mais now()
renvoie timestamp with time zone
. L'expression now() - '1 hour'::interval
est contraint à timestamp [without time zone]
, qui pose deux problèmes :
1.) Vous n'avez pas demandé celui-ci, mais l'expression n'est pas fiable. Son résultat dépend du paramètre de fuseau horaire actuel de la session dans laquelle la requête est exécutée. Détails ici :
Pour rendre l'expression claire, vous pouvez utiliser :
now() AT TIME ZONE 'Europe/London' -- your time zone here
Ou simplement (lire le manuel ici) :
LOCALTIMESTAMP -- explicitly take the local time
J'envisagerais de travailler avec timestamptz
à la place.
Aucun ne résout votre deuxième problème :
2.) Répondez à votre question. L'exclusion de contraintes ne fonctionne pas. Par documentation :
J'insiste sur moi.
now()
est l'implémentation Postgres de CURRENT_TIMESTAMP
. Comme vous pouvez le voir dans le catalogue système, il n'est que STABLE
, pas IMMUTABLE
:
SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';
proname | provolatile
--------+------------
now | s -- meaning: STABLE
Solutions
1.) Vous pouvez contourner la limitation en fournissant une constante dans le WHERE
condition (qui est toujours "immuable") :
select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp; -- derived from your example
2.) Soit en "simulant" une fonction immuable :
CREATE FUNCTION f_now_immutable()
RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC' -- your time zone here
$func$ LANGUAGE sql IMMUTABLE;
Et ensuite :
select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'
Faites attention à la façon dont vous l'utilisez cependant :while now()
est STABLE
(ne change pas pendant la durée d'une transaction), il fait changer entre les transactions, veillez donc à ne pas l'utiliser dans des instructions préparées (sauf en tant que valeur de paramètre) ou des index ou quoi que ce soit où cela pourrait vous mordre.
3.) Ou vous pouvez ajouter une constante apparemment redondante WHERE
clauses à votre requête actuelle qui correspondent à la contrainte sur votre 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;
Assurez-vous simplement que now() - '1 hour'::interval
tombe dans la bonne partition ou vous n'obtenez aucun résultat, évidemment.
A part :je préférerais utiliser cette expression dans CHECK
contraintes et requête. Plus facile à manipuler et fait la même chose :
created_at >= '2015-04-01 0:0'::timestamp
AND created_at < '2015-05-01 0:0'::timestamp