views:

64

answers:

2

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 value 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
+3  A: 

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.

eumiro
That looks good! I'm currently trying to find the right function to get the time of day from a datetime (it seems not to be TIME()). I will write again when I got a result.
Sven Koschnicke
okay, found it (on SO of course): CAST(datetime AS TIME) http://stackoverflow.com/questions/3724519/is-there-a-better-way-to-extract-the-time-of-day
Sven Koschnicke
wow, that works quite well! thank you! some conversion is needed. i post the working version in the original post.
Sven Koschnicke
+1  A: 

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.

Iain
I will look into function when I get the basic query working. Thanks for the idea!
Sven Koschnicke