【问题标题】:Query on a time range ignoring the date of timestamps查询忽略时间戳日期的时间范围
【发布时间】:2013-10-22 11:44:13
【问题描述】:

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

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

此表中有一个created_at 列,但如果不搜索特定日期,我不知道如何完成此操作。

我试过了:

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

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

【问题讨论】:

    标签: sql ruby-on-rails ruby postgresql rails-activerecord


    【解决方案1】:

    您只需使用 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 好答案,另一个要考虑的是时区。用户可能希望答案与他们自己的时区相对应。
    【解决方案2】:

    使用简单的转换为time

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

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

    考虑:

    • 包含/排除哪个边框。通常的做法是包含下边框和排除上边框。 BETWEEN 包括两者。

    • 确切的数据类型(timestamptimestamp with time zone)以及它与您当地时区的交互方式:

    索引

    如果您经常运行这些查询并且需要它们快速并且您的表不是很小,您将需要创建一个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));
    

    处理忽略年份的日期的类似问题:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-26
      • 1970-01-01
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      • 2021-11-15
      • 2014-02-11
      相关资源
      最近更新 更多