I have database table in PostgreSQL named as t1 like:
| Name | StartDate | EndDate |
|---|---|---|
| Oct-18 | 2018-10-01 | 2018-10-05 |
I want the result for the date range like:
| Oct-18 | 2018-10-01 | 2018-10-02 | 2018-10-03 | 2018-10-04 | 2018-10-05 |
|---|
with the help of generate_series() I can do it "vertically", but how to get the result in a single row?
Use generate_series(). But SQL does not allow a dynamic number of result columns. So you must wrap your result in a string, array or document type to make it work.
Example with an ARRAY constructor in a LATERAL subquery - in Postgres 10 or later:
SELECT t1.name, d.date_arr::date[]
FROM t1
LEFT JOIN LATERAL (
SELECT ARRAY(SELECT generate_series(t1.startdate::timestamp
, t1.enddate::timestamp
, interval '1 day'))
) d(date_arr) ON true;
Why (preferably) Postgres 10 or later?
Why the cast to timestamp?
Why LEFT JOIN .. ON true?
Though LEFT JOIN is not necessary in this particular case (could be CROSS JOIN) because the ARRAY constructor always returns a row.
LATERAL requires Postgres 9.3 or later. You can substitute with a correlated subquery:
SELECT name
, ARRAY(SELECT generate_series(startdate::timestamp
, enddate::timestamp
, interval '1 day')::date)
FROM t1;
Even works with pg 8.4:
db<>fiddle here
But consider upgrading to a current version.
crosstab()?crosstab() cannot overcome the static nature of SQL, either. There are limited workarounds with prepared row types ...
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