Query on a time range ignoring the date of timestamps

浪尽此生 提交于 2019-12-06 02:29:42

问题


I'm trying to query a purchases table in my rails database (Postgres) and I want to query on time ranges.

For example, I'd like to know how many purchases were made between 2 PM and 3 PM across all dates.

There is a created_at column in this table but I don't see how to accomplish this without searching for a specific date as well.

I've tried:

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

But this ultimately will just search for today's date with those times.


回答1:


You need to extract just the hour portion from created_at using PostgreSQL's date_part/extract function.

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

For example, something like this:

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



回答2:


Use a simple cast to time:

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

This way you can easily test against arbitrary times.

Consider:

  • Which border to include / exclude. Common practice is to include the lower border and exclude the upper. BETWEEN includes both ...

  • The exact data type (timestamp or timestamp with time zone) and how that interacts with your local time zone:
    Ignoring timezones altogether in Rails and PostgreSQL

Index

If you run these queries a lot and need them fast and your table isn't very small, you will want to create a functional index for performance:

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

Note:

  • I used the standard SQL syntax cast() instead of the Postgres syntactical shortcut ::. This is required for indices.

  • This index works for a timestamp [without time zone] since the cast is IMMUTABLE as required for an index. But it does not work for a timestamp with time zone, for the same reasons. You can fix this, but you need to define what you need exactly. Use the AT TIME ZONE construct to define the time zone to extract the time for. For instance, to measure against UTC time:

CREATE INDEX tbl_created_at_time_idx2
ON tbl(cast(created_at AT TIME ZONE 'UTC' AS time));

Similar question dealing with dates ignoring the year:
How do you do date math that ignores the year?



来源:https://stackoverflow.com/questions/19368205/query-on-a-time-range-ignoring-the-date-of-timestamps

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!