sql >> Database >  >> RDS >> PostgreSQL

Partities snoeien op basis van controlebeperking werkt niet zoals verwacht

Uw kolom created_at is timestamp without time zone .

Maar now() retourneert timestamp with time zone . De uitdrukking now() - '1 hour'::interval wordt gedwongen tot timestamp [without time zone] , met twee problemen :

1.) Je hebt hier niet om gevraagd, maar de uitdrukking is onbetrouwbaar. Het resultaat hangt af van de huidige tijdzone-instelling van de sessie waarin de query wordt uitgevoerd. Details hier:

Om de uitdrukking duidelijk te maken, kunt u het volgende gebruiken:

now() AT TIME ZONE 'Europe/London' -- your time zone here

Of gewoon (lees de handleiding hier) :

LOCALTIMESTAMP  -- explicitly take the local time

Ik zou overwegen om te werken met timestamptz in plaats daarvan.
Geen van beide lost uw tweede probleem op:

2.) Antwoord op uw vraag. Beperking uitsluiting werkt niet. Per documentatie:

Vetgedrukte nadruk van mij.

now() is de Postgres-implementatie van CURRENT_TIMESTAMP . Zoals je kunt zien in de systeemcatalogus, is het alleen STABLE , niet IMMUTABLE :

SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';

proname | provolatile
--------+------------
now     | s              -- meaning: STABLE

Oplossingen

1.) U kunt de beperking omzeilen door een constante op te geven in de WHERE voorwaarde (die altijd "onveranderlijk" is):

select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp;  -- derived from your example

2.) Of door een onveranderlijke functie te "faken":

CREATE FUNCTION f_now_immutable()
  RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC'  -- your time zone here
$func$  LANGUAGE sql IMMUTABLE;

En dan:

select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'

Wees echter voorzichtig met hoe je dit gebruikt:while now() is STABLE (verandert niet voor de duur van een transactie), wel wissel tussen transacties, dus zorg ervoor dat u dit niet gebruikt in voorbereide verklaringen (behalve als parameterwaarde) of indexen of iets anders waar het u zou kunnen bijten.

3.) Of je kunt schijnbaar overbodige constante WHERE . toevoegen clausules voor uw huidige zoekopdracht die overeenkomen met de beperking op uw partitie:

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;

Zorg ervoor dat u now() - '1 hour'::interval valt in de juiste partitie of je krijgt natuurlijk geen resultaten.

Terzijde:ik zou deze uitdrukking liever gebruiken in CHECK beperkingen en vragen. Makkelijker te hanteren en doet hetzelfde:

       created_at >= '2015-04-01 0:0'::timestamp
AND    created_at <  '2015-05-01 0:0'::timestamp



  1. Algemene fout:1366 Onjuiste integerwaarde met Doctrine 2.1 en Zend Form-update

  2. Odd INNER JOIN syntaxis en inkapseling

  3. Waarom geeft mysqli de foutmelding 'Commands out of sync'?

  4. Een tijdstempel converteren naar een geheel getal (Unix-tijdperk) in Postgres