If 1 Redshift would support the basic form of generate_series()
, this might work. At least this works in Postgres 8.3:
SELECT CASE WHEN split > 0 AND g = 0 THEN usage_from
WHEN split > 0 AND g = 1 THEN usage_till::date + '2:0'::time
ELSE usage_from END
, CASE WHEN split > 0 AND g = 0 THEN usage_till::date + '2:0'::time
WHEN split > 0 AND g = 1 THEN usage_till
ELSE usage_till END
FROM (
SELECT * , generate_series(0, split) AS g
FROM (
SELECT *
, (usage_till - '2:0'::time)::date
- (usage_from - '2:0'::time)::date AS split -- results in integer
FROM t
) sub1
) sub2
How?
In the inner subquery
sub1
I find whether the time range crosses 2 a.m. and save that in the columnsplit
. I am assuming the time range never crosses 2 a.m. twice, but the query could easily be adapted to that.generate_series()
automatically generates 1 row per wrap around.In the next subquery
sub2
generate_series()
generates two rows where a split is needed.In the outer SELECT a CASE statement adjusts the timestamps accordingly.
Normally I would use
interval '2 hours'
instead of'2:0'::time
, but I seem to remember Redshift doesn't support theinterval
type.
Not in Redshift?
If Redshift only allows generate_series()
in the FROM
list and not in the SELECT
list, you are out of luck. This already is the ancient form. In modern Postgres, you would use a LATERAL JOIN
. You could try your luck with regexp_split_to_table(), but that's not in Postgres 8.0 either.
1 But the manual says, generate_series()
is unsupported.
Barring that, I can only think of a procedural solution with PL/pgSQL. But Redshift might be limited there, too ...