sql >> Databáze >  >> RDS >> PostgreSQL

Prořezávání oddílu na základě kontrolního omezení nefunguje podle očekávání

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



  1. Jak používat nastavení tcp_keepalives v Postgresql?

  2. SQLskills Wait Types Library nyní zobrazuje data SentryOne

  3. SQL:Vyberte 3 nejlepší záznamy + součet množství

  4. Ladit PDO mySql vložit NULL do databáze místo prázdné