Kolom Anda created_at
adalah timestamp without time zone
.
Tapi now()
mengembalikan timestamp with time zone
. Ekspresi now() - '1 hour'::interval
sedang dipaksa untuk timestamp [without time zone]
, yang membawa dua masalah :
1.) Anda tidak meminta yang ini, tetapi ekspresinya tidak dapat diandalkan. Hasilnya tergantung pada pengaturan zona waktu saat ini dari sesi tempat kueri dieksekusi. Detailnya di sini:
Untuk memperjelas ekspresi, Anda dapat menggunakan:
now() AT TIME ZONE 'Europe/London' -- your time zone here
Atau cukup (baca manualnya di sini) :
LOCALTIMESTAMP -- explicitly take the local time
Saya akan mempertimbangkan untuk bekerja dengan timestamptz
sebagai gantinya.
Keduanya tidak menyelesaikan masalah kedua Anda:
2.) Jawab pertanyaan Anda. Pengecualian batasan tidak berfungsi. Per dokumentasi:
Penekanan saya yang berani.
now()
adalah implementasi Postgres dari CURRENT_TIMESTAMP
. Seperti yang Anda lihat di katalog sistem, hanya STABLE
, bukan IMMUTABLE
:
SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';
proname | provolatile
--------+------------
now | s -- meaning: STABLE
Solusi
1.) Anda dapat mengatasi batasan dengan memberikan konstanta di WHERE
kondisi (yang selalu "tidak berubah"):
select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp; -- derived from your example
2.) Atau dengan "memalsukan" fungsi yang tidak dapat diubah:
CREATE FUNCTION f_now_immutable()
RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC' -- your time zone here
$func$ LANGUAGE sql IMMUTABLE;
Dan kemudian:
select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'
Hati-hati bagaimana Anda menggunakan ini:while now()
adalah STABLE
(tidak berubah selama durasi transaksi), tidak perubahan di antara transaksi, jadi berhati-hatilah untuk tidak menggunakannya dalam pernyataan yang disiapkan (kecuali sebagai nilai parameter) atau indeks atau apa pun yang dapat mengganggu Anda.
3.) Atau Anda dapat menambahkan konstanta yang tampaknya berlebihan WHERE
klausa untuk kueri Anda saat ini yang cocok dengan batasan pada partisi Anda:
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;
Pastikan sendiri bahwa now() - '1 hour'::interval
jatuh ke partisi yang tepat atau Anda tidak mendapatkan hasil, tentu saja.
Selain:Saya lebih suka menggunakan ekspresi ini di CHECK
kendala dan permintaan. Lebih mudah untuk menangani dan melakukan hal yang sama:
created_at >= '2015-04-01 0:0'::timestamp
AND created_at < '2015-05-01 0:0'::timestamp