开发者

SQL: select one record for each day nearest to a specific time

I have one table that stores values with a point in time:

CREATE TABLE values
(
    value DECIMAL,
    datetime DATETIME 
)

There may be many values on each day, there may also be only one value for a given day. Now I want to get the value for each day in a given timespan (e.g. one month) which is nearest to a given time of day. I only want to get one value per day if there are records for this day or no va开发者_Go百科lue if there are no records. My database is PostgreSQL. I'm quite stuck with that. I could just get all values in the timespan and select the nearest value for each day programmatically, but that would mean to pull a huge amount of data from the database, because there can be many values on one day.

(Update)

To formulate it a bit more abstract: I have data of arbitrary precision (could be one minute, could be two hours or two days) and I want to convert it to a fixed precision of one day, with a specific time of day.

(second update)

This is the query from the accepted answer with correct postgresql type converstions, assuming the desired time is 16:00:

SELECT datetime, value FROM values, (
  SELECT DATE(datetime) AS date, MIN(ABS(EXTRACT(EPOCH FROM TIME '16:00' - CAST(datetime AS TIME)))) AS timediff
  FROM values
  GROUP BY DATE(datetime)
  ) AS besttimes
WHERE 
CAST(values.datetime AS TIME) BETWEEN TIME '16:00' - CAST(besttimes.timediff::text || ' seconds' AS INTERVAL)
                                AND TIME '16:00' + CAST(besttimes.timediff::text || ' seconds' AS INTERVAL) 
                                AND DATE(values.datetime) = besttimes.date


How about going into this direction?

SELECT values.value, values.datetime
FROM values,
( SELECT DATE(datetime) AS date, MIN(ABS(_WANTED_TIME_ - TIME(datetime))) AS timediff
  FROM values
  GROUP BY DATE(datetime)
) AS besttimes
WHERE TIME(values.datetime) BETWEEN _WANTED_TIME_ - besttimes.timediff
                                AND _WANTED_TIME_ + besttimes.timediff
AND DATE(values.datetime) = besttimes.date

I am not sure about the date/time extracting and abs(time) functions, so you will have to replace them probably.


It appears you have two parts to solve:

  1. Are there any results for a day at all?

  2. If there are, then which is the nearest one?

By shortcircuiting the process at part 1 if you have no results you'll save a lot of execution time.

The next thing to note is that you don't have to pull the data from the database, wait until you have an answer or not by using PLSQL functions (or something else) to work it out on the server first.

Once you have a selection of times to check you can use intervals to compare them. Check the Postgres docs on intervals and datetime functions for precise instructions, but basically you minus the selected dates from the date you've given and the one with the smallest interval is the one you want.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜