This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the fastest way to truncate timestamps to 5 minutes in Postgres?
Postgresql SQL GROUP BY time interval with arbitrary accuracy (down to milli seconds)
I want to aggregate data at 5 minute intervals in PostgreSQL. If I use the date_trunc() function, I can aggregate data at an hourly, monthly, daily, weekly, etc. interval but not a specific interval like 5 minute or 5 days.
select date_trunc('hour', date1), count(*) from table1 group by 1;
How can we achieve this in PostgreSQL?
SELECT date_trunc('hour', date1) AS hour_stump
, (extract(minute FROM date1)::int / 5) AS min5_slot
, count(*)
FROM table1
GROUP BY 1, 2
ORDER BY 1, 2;
You could GROUP BY two columns: a timestamp truncated to the hour and a 5-minute-slot.
The example produces slots 0 - 11. Add 1 if you prefer 1 - 12.
I cast the result of extract() to integer, so the division / 5 truncates fractional digits. The result:
minute 0 - 4 -> slot 0
minute 5 - 9 -> slot 1
etc.
This query only returns values for those 5-minute slots where values are found. If you want a value for every slot or if you want a running sum over 5-minute slots, consider this related answer:
PostgreSQL: running count of rows for a query 'by minute'
Here's a simple query you can either wrap in a function or cut and paste all over the place:
select now()::timestamp(0), (extract(epoch from now()::timestamptz(0)-date_trunc('d',now()))::int)/60;
It'll give you the current time, and a number from 0 to the n-1 where n=60 here. To make it every 5 minutes, make that number 300 and so on. It groups by the seconds since the start of the day. To make it group by seconds since year begin, hour begin, or whatever else, change the 'd' in the date_trunc.
Related
I need random interval time between 0 and (10 days and 5 hours).
My code:
select random() * (interval '10 days 5 hours')
from generate_series(1, 50)
It works like should, except a few strange results, like:
0 years 0 mons 7 days 26 hours 10 mins 1.353353 secs
The problem is 26 hours, it shouldn't be more than 23. And I never get 10 days, what I'd like to.
Intervals in Postgres are quite flexible, so hour values of greater than 23 do not necessarily roll over to days. Use jusify_interval() to return them to the normal "days" and "hours"."
So:
select justify_interval(random() * interval '10 day 5 hour')
from generate_series(1, 200)
order by 1 desc;
will return values with appropriate values for days, hours, minutes, and seconds.
Now, why aren't you getting intervals with more than 10 days? This is simple randomness. If you increase the number of rows to 200 (as above), you'll see them (in all likelihood). If you run the code multiple times, sometimes you'll see none in that range; sometimes you'll see two.
Why? You are asking how often you get a value of 240+ in a range of 245. Those top 5 hours account for 0.02% of the range (about 1/50). In other words a sample of 50 is not big enough -- any given sample of 50 random values is likely to be missing 1 or more 5 hour ranges.
Plus, without justify_interval(), you are likely to miss those anyway because they may show up as 9 days with an hours component larger than 23.
Try this:
select justify_hours(random() * (interval '245 hours'))
FROM generate_series(1, 50)
See Postgres Documentation for an explanation of the justify_* functions.
One option would be to use an interval of one hour, and then multiply by the random number between 0 and 1 coming from the series:
select random() * 245 * interval '1 hour'
from generate_series(1, 50);
I can see that the other answers suggest using justify_interval. If you just want a series of intervals between 0 and 245 hours (245 hours corresponding to 10 days and 5 hours), then my answer should suffice.
I am creating a table which will have 2 columns:
Day_time (time from 1978-01-01 00:00:00 Sunday, till 1978-01-07 23:59:00.0 Saturday, Granularity: Minute)
Time_id (a unique id for each minute), to be populated
I have column one populated. I want to populate column two.
How I am doing it right now:
EXTRACT(dayofweek FROM day_time) * 10000 + DATEDIFF('minutes', TRUNC(day_time), day_time)
I basically want a function where I pass any date and it tells me where I am in a week. So, I need a function, just like the function above. Just more optimized, where I give a date and get a unique ID. The unique ID should repeat weekly.
Example: ID for Jan 1, 2015 00:00:00 will be same as Jan 8, 2015 00:00:00.
Why 1978-01-01? cuz it starts from a Sunday.
Why 10,000? cuz the number of minutes in a day are in four digits.
You can do it all in one fell swoop, without needing to extract the date separately:
SELECT DATEDIFF('minutes', date_trunc('week',day_time), day_time) which I'd expect to be marginally faster.
Another approach that I'd expect to be significantly faster would be converting the timestamp to epoch, dividing by 60 to get minutes from epoch and then taking the value modulus of 10,080 (for 60 * 24 * 7 minutes in a week).
SELECT (extract(epoch from day_time) / 60) % 10080
If you don't care about the size of the weekly index, you could also do:
SELECT (extract(epoch from day_time)) % 604800 and skip the division step altogether, which should make it faster still.
This question already has answers here:
How to add a variable number of hours to a date in PostgreSQL?
(5 answers)
Closed 8 years ago.
I would like to do a query in postgres which should bring count of records that updated previous one hour
For example 9AM-10AM records updated is 100 means I should get 100.
10AM-11AM records update is 200 means I should get 200(not 300).
Sample time stamp in updated column 2011-02-03 09:00:00
I have tried like this
select count(*) from customer where updated>=now()-1 and updated<now()
I know now()-1 will take yesterday. I dont know how to minus one hour from now
This should be doable using the date/time related functions and operations provided by Postgres:
where updated between
(date_trunc('hour',current_timestamp) - interval '1 hour')
and
(date_trunc('hour',current_timestamp))
Explanation:
date_trunc('hour',current_timestamp)
Gives the current time with minutes, seconds and milliseconds set to 0, and
- interval '1 hour'
subtracts one hour from a given timestamp.
Combine those to create the range you want ( between )
I am using Postgres v9.2.6.
Have a system with lots of devices that take measurements. These measurements are stored in
table with three fields.
device_id
measurement (Indexed)
time (Indexed)
There could be 10 Million measurements in a single year. Most of the time the user is only interested in 100 min max pairs within equal interval for a certain period, for example in last 24 hours or in last 53 weeks. To get these 100 mins and maxs the period is divided into 100 equal intervals. From each interval min and max is extracted. Would you recommend the most efficient approach to query the data? So far I have tried the following query:
WITH periods AS (
SELECT time.start AS st, time.start + (interval '1 year' / 100) AS en FROM generate_series(now() - interval '1 year', now(), interval '1 year' / 100) AS time(start)
)
SELECT * FROM sample_data
JOIN periods
ON created_at BETWEEN periods.st AND periods.en AND
customer_id = 23
WHERE
sample_data.id = (SELECT id FROM sample_data WHERE created_at BETWEEN periods.st AND periods.en ORDER BY sample ASC LIMIT 1)
This test approach took over a minute for 1 million points on MacBook Pro.
Thanks...
Sorry about that. It was actually my question and looks like the author of this post caught cold so I ca not ask him to edit it. I've posted "more good" question here - Slow PostgreSQL Query for Mins and Maxs within equal intervals in a time period. Could you please close this question?
I have a table with measures and the time this measures have been taken in the following form: MM/DD/YYYY HH:MI:SS AM. I have measures over many days starting at the same time every day.The datas are minute by minute so basically the seconds are always = 0. I want to select only the measures for the first 5 minutes of each day. I would have used the where statement but the condition would only be on the minutes and note the date is there a way to do this?
Thanks
You could try something like this:
SELECT * FROM SomeTable
WHERE
DATEPART(hh, timestamp_col) = 0 AND -- filter for first hour of the day
DATEPART(mm, timestamp_col) <= 5 -- filter for the first five minutes
Careful! 0 means midnight. If your "first hour" of the day is actually 8 or 9 AM then you should replace the 0 with an 8 or 9.