Cột của bạn created_at
là timestamp without time zone
.
Nhưng now()
trả về timestamp with time zone
. Biểu thức now() - '1 hour'::interval
đang bị ép buộc vào timestamp [without time zone]
, mang theo hai vấn đề :
1.) Bạn đã không yêu cầu điều này, nhưng biểu hiện là không đáng tin cậy. Kết quả của nó phụ thuộc vào cài đặt múi giờ hiện tại của phiên truy vấn đang được thực thi. Chi tiết tại đây:
Để làm cho biểu thức rõ ràng, bạn có thể sử dụng:
now() AT TIME ZONE 'Europe/London' -- your time zone here
Hoặc chỉ cần (đọc hướng dẫn tại đây) :
LOCALTIMESTAMP -- explicitly take the local time
Tôi sẽ cân nhắc làm việc với timestamptz
thay vào đó.
Không giải quyết được vấn đề thứ hai của bạn:
2.) Câu trả lời cho câu hỏi của bạn. Loại trừ ràng buộc không hoạt động. Theo tài liệu:
Nhấn mạnh đậm của tôi.
now()
là triển khai Postgres của CURRENT_TIMESTAMP
. Như bạn có thể thấy trong danh mục hệ thống, nó chỉ là STABLE
, không phải IMMUTABLE
:
SELECT proname, provolatile FROM pg_proc WHERE proname = 'now';
proname | provolatile
--------+------------
now | s -- meaning: STABLE
Giải pháp
1.) Bạn có thể khắc phục hạn chế bằng cách cung cấp một hằng số trong WHERE
điều kiện (luôn là "không thay đổi"):
select count(*) from events
where created_at > '2015-05-25 15:49:20.037815'::timestamp; -- derived from your example
2.) Hoặc bằng cách "giả mạo" một hàm bất biến:
CREATE FUNCTION f_now_immutable()
RETURNS timestamp AS
$func$
SELECT now() AT TIME ZONE 'UTC' -- your time zone here
$func$ LANGUAGE sql IMMUTABLE;
Và sau đó:
select count(*) from events
where created_at > f_now_immutable() - interval '1 hour'
Hãy cẩn thận với cách bạn sử dụng điều này mặc dù:while now()
là STABLE
(không thay đổi trong suốt thời gian giao dịch), nó không thay đổi giữa các giao dịch, vì vậy hãy cẩn thận không sử dụng điều này trong các câu lệnh đã chuẩn bị sẵn (ngoại trừ dưới dạng giá trị tham số) hoặc chỉ mục hoặc bất kỳ thứ gì mà nó có thể cắn bạn.
3.) Hoặc bạn có thể thêm hằng số dường như dư thừa WHERE
mệnh đề cho truy vấn hiện tại của bạn phù hợp với ràng buộc trên phân vùng của bạn:
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;
Chỉ cần đảm bảo rằng now() - '1 hour'::interval
rơi vào đúng phân vùng hoặc bạn không nhận được kết quả rõ ràng.
Ngoài ra:Tôi muốn sử dụng biểu thức này trong CHECK
ràng buộc và truy vấn. Dễ dàng xử lý hơn và thực hiện tương tự:
created_at >= '2015-04-01 0:0'::timestamp
AND created_at < '2015-05-01 0:0'::timestamp