我正在尝试查询我的rails数据库中的购买表(Postgres),我想查询时间范围。
例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。
此表格中有一个created_at
列,但我不知道如何在不搜索特定日期的情况下完成此操作。
我试过了:
Purchases.where("created_at BETWEEN ? and ?", Time.now - 1.hour, Time.now)
但这最终只会在那些时候搜索今天的日期。
答案 0 :(得分:6)
您需要使用PostgreSQL's date_part/extract function从created_at中提取小时部分。
SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 20
例如,像这样:
Purchases.where(["EXTRACT(HOUR FROM created_at) BETWEEN ? AND ?", 13, 14])
答案 1 :(得分:3)
使用简单的强制转换为time
:
Purchases.where("created_at::time >= ?
AND created_at::time < ?", Time.now - 1.hour, Time.now)
通过这种方式,您可以轻松地对任意时间进行测试。
考虑:
要包含/排除哪个边框。通常的做法是包含下边框,排除上边框。 BETWEEN
包括两者......
确切的数据类型(timestamp
或timestamp with time zone
)以及与当地时区的互动方式:
Ignoring timezones altogether in Rails and PostgreSQL
如果您经常运行这些查询并快速需要它们,而且您的表格不是很小,那么您需要为性能创建functional index:
CREATE INDEX tbl_created_at_time_idx ON tbl (cast(created_at AS time));
注意:
我使用了standard SQL syntax cast()
instead of the Postgres syntactical shortcut ::
。这是索引所必需的。
此索引适用于timestamp [without time zone]
,因为转化为IMMUTABLE
,因为索引需要。但出于同样的原因,它对timestamp with time zone
不起作用。您可以解决此问题,但您需要准确定义所需内容。使用AT TIME ZONE
构造来定义提取时间的时区。例如,要根据UTC时间进行衡量:
CREATE INDEX tbl_created_at_time_idx2
ON tbl(cast(created_at AT TIME ZONE 'UTC' AS time));
处理忽略年份的日期的类似问题:
How do you do date math that ignores the year?