查询忽略时间戳日期的时间范围

我正在尝试查询我的rails数据库(Postgres)中的购买表,我想查询时间范围。

例如,我想知道在所有日期的下午2点到下午3点之间进行了多少次购买。

此表中有一个created_at列,但我没有看到如何在不搜索特定日期的情况下完成此操作。

我试过了:

Purchases.where("created_at BETWEEN ? and ?", Time.now - 1.hour, Time.now)

但这最终只会在那些时候搜索今天的日期。

您需要使用PostgreSQL的date_part / extract函数从created_at中提取小时部分。

http://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT

 SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40'); Result: 20 

例如,像这样:

 Purchases.where(["EXTRACT(HOUR FROM created_at) BETWEEN ? AND ?", 13, 14) 

使用简单的演员time

 Purchases.where("created_at ::time >= ? AND created_at ::time < ?", Time.now - 1.hour, Time.now) 

这样您就可以轻松地对任意时间进行测试。

考虑:

  • 包含/排除哪个边框。 通常的做法是包括下边界并排除鞋面。 BETWEEN 包括 ......

  • 确切的数据类型( timestamp with time zone timestamptimestamp with time zone )以及与当地时区的交互方式:
    在Rails和PostgreSQL中完全忽略时区

指数

如果你经常运行这些查询并且需要它们快速而且表格不是很小,那么你需要为性能创建一个function索引

 CREATE INDEX tbl_created_at_time_idx ON tbl (cast(created_at AS time)); 

注意:

  • 我使用标准的SQL语法cast()而不是Postgres语法快捷方式:: 。 这是指数所必需的。

  • 此索引适用于timestamp [without time zone]因为IMMUTABLE是索引所需的IMMUTABLE 。 但出于同样的原因,它不适用于timestamp with time zonetimestamp 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)); 

处理忽略年份的日期的类似问题:
你怎么做数学忽略年份?