I'd like to get the list of days between the two dates (including them) in a PostgreSQL database. For example, if I had:
then the result should be:
29 june 2012
30 june 2012
1 july 2012
2 july 2012
3 july 2012
What would be the best way of doing this in PostgreSQL?
Thanks.
In Postgresql, we can find the date range between the timestamp using the BETWEEN clause. In this section, we will use the table named journey, and a description of the table is given below.
Enter the simple but handy set returning function of Postgres: generate_series . generate_series as the name implies allows you to generate a set of data starting at some point, ending at another point, and optionally set the incrementing value. generate_series works on two datatypes: integers. timestamps.
The PostgreSQL BETWEEN condition will return the records where expression is within the range of value1 and value2 (inclusive).
select CURRENT_DATE + i
from generate_series(date '2012-06-29'- CURRENT_DATE,
date '2012-07-03' - CURRENT_DATE ) i
or even shorter:
select i::date from generate_series('2012-06-29',
'2012-07-03', '1 day'::interval) i
As timestamp
:
select generate_series('2012-06-29', '2012-07-03', '1 day'::interval);
generate_series
------------------------
2012-06-29 00:00:00-03
2012-06-30 00:00:00-03
2012-07-01 00:00:00-03
2012-07-02 00:00:00-03
2012-07-03 00:00:00-03
or casted to date
:
select (generate_series('2012-06-29', '2012-07-03', '1 day'::interval))::date;
generate_series
-----------------
2012-06-29
2012-06-30
2012-07-01
2012-07-02
2012-07-03
This should do it:
select date '2012-06-29' + i
from generate_series(1, (select date '2012-07-3' - date '2012-06-29')) i
If you don't want to repeat the start_date in the subselect things get a bit more complicated:
with min_max (start_date, end_date) as (
values (date '2012-06-29', date '2012-07-3')
), date_range as (
select end_date - start_date as duration
from min_max
)
select start_date + i
from min_max
cross join generate_series(1, (select duration from date_range)) i;
(See maniek's answer for a much better version of the "no-repeat" problem)
select generate_series('2012-06-29', '2012-07-03', '1 day'::interval)::date;
For things like this its generally handy to have a dates table in the system.
Just like a numbers table they can be very useful and quicker to use than generating the dates on the fly, especially when you scale up to large data sets.
Such a date table from 1900 to 2100 will be very small, so there isn't much over head in storage.
Edit: Dunno why this is getting voted down, it will probably be the best for performance. Plus it has so many other advantages. Want to link orders to a an quarters performance numbers? Its a simple link between the tables. (Order.OrderDate -> Dates.Date -> Dates.Quarter -> PerformanceTotal.Quarter) etc. Its the same for dealing with working days, like the last working day of a month, or the first Tuesday of the previous month. Like a numbers table, I'd strongly recommend them!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With