15

I'm trying to find the snowflake equivalent of generate_series() (the PostgreSQL syntax).

SELECT generate_series(timestamp '2017-11-01', CURRENT_DATE, '1 day')
Tarik
  • 167
  • 1
  • 2
  • 6

7 Answers7

23

Just wanted to expand on Marcin Zukowski's comment to say that these gaps started to show up almost immediately after using a date range generated this way in a JOIN.

We ultimately ended up doing this instead!

select
  dateadd(
    day,
    '-' || row_number() over (order by null),
    dateadd(day, '+1', current_date())
  ) as date
from table (generator(rowcount => 90))
bcrowell
  • 499
  • 4
  • 7
  • I think this is the best answer since it should generate the dates with no gaps for a large number of rows. – Simon D Sep 26 '19 at 14:48
7

I had a similar problem and found an approach, which avoids the issue of a generator requiring a constant value by using a session variable in addition to the already great answers here. This is closest to the requirement of the OP to my mind.

-- set parameter to be used as generator "constant" including the start day
set num_days =  (Select datediff(day, TO_DATE('2017-11-01','YYYY-MM-DD'), current_date()+1));
-- use parameter in bcrowell's answer now
select
  dateadd(
    day,
    '-' || row_number() over (order by null),
    dateadd(day, '+1', current_date())
  ) as date
from table (generator(rowcount => ($num_days)));
-- clean up previously set variable
unset num_days;
kf06925
  • 371
  • 3
  • 5
5
WITH RECURSIVE rec_cte AS (
    -- start date
    SELECT '2017-11-01'::DATE as dt
    UNION ALL
    SELECT DATEADD('day',1,dt) as dt
    FROM rec_cte
    -- end date (inclusive)
    WHERE dt < current_date()
)
SELECT * FROM rec_cte
iljau
  • 2,151
  • 3
  • 22
  • 45
  • 1
    Exactly like what was explained here https://popsql.com/learn-sql/snowflake/how-to-avoid-gaps-in-data-in-snowflake – Mehdi Oct 27 '22 at 16:09
2

Adding this answer for completitude, in case you have an initial and last date:

select -1 + row_number() over(order by 0) i, start_date + i generated_date 
from (select '2020-01-01'::date start_date, '2020-01-15'::date end_date)
join table(generator(rowcount => 10000 )) x
qualify i < 1 + end_date - start_date
Felipe Hoffa
  • 54,922
  • 16
  • 151
  • 325
2

Using ARRAY_GENERATE_RANGE and date arithmetic:

SET (start_date, end_date) = (SELECT '2017-11-01', CURRENT_DATE());

SELECT $start_date::DATE + VALUE::INT AS value
FROM TABLE(FLATTEN(ARRAY_GENERATE_RANGE(0, DATEDIFF('DAY',$start_date,$end_date)+1)));
-- VALUE
-- 2017-11-01
-- 2017-11-02
-- ...
-- 2023-04-29
-- 2023-04-30
Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
1

I found the generator function in Snowflake quite limiting for all but the simplest use cases. For example, it was not clear how to take a single row specification, explode it into a table of dates and join it back to the original spec table.

Here is an alternative that uses recursive CTEs.

-- A 2 row table that contains "specs" for a date range
create local temp table date_spec as
    select 1 as id, '2022-04-01'::date as start_date, current_date() as end_date
    union all
    select 2, '2022-03-01', '2032-03-30'
;

with explode_date(id, date, next_date, end_date) as (
    select
        id
      , start_date as date          -- start_date is the first date
      , date + 1 as next_date       -- next_date is the date of for the subsequent row in the recursive cte
      , end_date
    from date_spec

    union all

    select
        ds.id
      , ed.next_date                -- the current_date is the value of next_date from above
      , ed.next_date + 1
      , ds.end_date
    from date_spec ds
    join explode_date ed
      on ed.id = ds.id
    where ed.date <= ed.end_date    -- keep running until you hit the end_date
)

select * from explode_date
order by id, date desc
;
teemoleen
  • 118
  • 6
-2

This is how I was able to generate a series of dates in Snowflake. I set row count to 1095 to get 3 years worth of dates, you can of course change that to whatever suits your use case

select 
    dateadd(day, '-' || seq4(), current_date()) as dte 
from 
    table 
       (generator(rowcount => 1095))

Originally found here

EDIT: This solution is not correct. seq4 does not guarantee a sequence without gaps. Please follow other answers, not this one. Thanks @Marcin Zukowski for pointing that out.

Peter Fine
  • 2,873
  • 3
  • 14
  • 16
watersbythebay
  • 136
  • 2
  • 5
  • Are you after generating a series of dates ? if so you can do this select current_date() - seq4() from table(generator(rowcount => 10)) v .. seq4 will generate sequence starting with 0, rowcount is the number of rows you want to generate .. more here https://docs.snowflake.net/manuals/sql-reference/functions/generator.html – Fact Jan 25 '19 at 06:37
  • 3
    Warning: this should work for short sequences, but remember that SEQ is not guaranteed to produce a dense sequence - if you produce millions of records, there will likely be holes. – Marcin Zukowski Jan 31 '19 at 22:46
  • 2
    To further @MarcinZukowski's comment, these gaps are not theoretical, and they depend on the size of your warehouse. seq4 should never be expected to create a dense sequence. the other answers to this question avoid this problem. – Peter Fine Mar 19 '20 at 12:40
  • I wish I'd seen these comments earlier, we started seeing these gaps and had to go through support to understand them. Thnks for your comments - my solution is not correct at all! – Peter Fine Jun 18 '20 at 16:30