Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I construct an array of dates in a given date range using snowsql?

Given two dates, I would like to create an array that holds all of the days between those dates and then filter it to contain only the days that fall at the end of a month.

For example, with start_date 2019-01-31 and end_date 2019-06-30, I would to construct the array

[
  '2019-01-31',
  '2019-02-28',
  '2019-03-31',
  '2019-04-30',
  '2019-05-31',
  '2019-06-30'
]
like image 896
Sains Avatar asked Nov 11 '19 02:11

Sains


People also ask

How do you use a date range for a Snowflake?

The default is TIMESTAMP_NTZ. For DATE and TIMESTAMP data, Snowflake recommends using years between 1582 and 9999. Snowflake accepts some years outside this range, but years prior to 1582 should be avoided due to limitations on the Gregorian Calendar.

How do you put an array of data into a Snowflake?

To insert arrays of values into a column I am using the ARRAY_CONSTUCT function and to insert the structures/dictionaries/objects I am using the OBJECT_CONSTRUCT function. E.g. Inserting a single row using this syntax works: insert into "MY_DB".

How do you get a list of weeks between date ranges?

To calculate the number of weeks between two dates, start by counting the number of days between the start and end date. Then, divide that number by 7 days per week.

How do you make a date series Snowflake?

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 docs.snowflake.net/manuals/sql-reference/functions/…


3 Answers

It's a little hard to understand exactly what you want, but from the requested output it looks like the array contains monthly dates between two date limits. I tried to implement using JavaScript to avoid the dreaded "Unsupported subquery" error, but it's hard to calculate dates, format them and return from JavaScript to SQL.
So I ended up with an SQL UDF:

CREATE OR REPLACE FUNCTION ARRAY_MONTHS_BETWEEN("FROM" DATE, "TO" DATE)
RETURNS ARRAY AS 
'
  SELECT ARRAY_AGG(DATEADD(MONTH, "MONTH" , "FROM")) A
  FROM (SELECT ROW_NUMBER() OVER (ORDER BY NULL) - 1 "MONTH"
        FROM TABLE(GENERATOR(ROWCOUNT => 1000)))
  WHERE "MONTH" <= CEIL(DATEDIFF(MONTHS, "FROM", "TO"))
';

It can be tricky to use this function except with date constants, because you risk opening Pandora's box of Snowflake correlated subqueries. But then again, maybe not.

like image 64
Hans Henrik Eriksen Avatar answered Oct 21 '22 19:10

Hans Henrik Eriksen


The Snowflake LAST_DAY function can be used to fetch the last day of every month that is between the two dates https://docs.snowflake.net/manuals/sql-reference/functions/last_day.html.

SELECT 
  ARRAY_AGG(LAST_DAY(MY_DATE))
FROM (
  SELECT
    LAST_DAY(DATEADD(MONTH, SEQ4(), '2019-01-31')) AS MY_DATE
  FROM TABLE(GENERATOR(ROWCOUNT=>20000))
  WHERE MY_DATE <= '2019-06-30'
);

The above query will also wrap the result in an array https://docs.snowflake.net/manuals/sql-reference/functions/array_agg.html

[
  "2019-01-31",
  "2019-02-28",
  "2019-03-31",
  "2019-04-30",
  "2019-05-31",
  "2019-06-30"
]

As already suggested, you can optionally use this sql to create a new user-defined function:

CREATE FUNCTION LAST_DATES_TO_ARRAY(FROM_D DATE, TO_D DATE)
RETURNS ARRAY 
AS 
$$
SELECT ARRAY_AGG(LAST_DAY(MY_DATE))
FROM (
  SELECT
    LAST_DAY(DATEADD(MONTH, SEQ4(), FROM_D)) AS MY_DATE
  FROM TABLE(GENERATOR(ROWCOUNT=>20000))
  WHERE MY_DATE <= TO_D
)
$$;
like image 6
FedSic Avatar answered Oct 21 '22 20:10

FedSic


Building on what previous responders have provided, the following should work for you.

CREATE OR REPLACE FUNCTION LAST_DATES_TO_ARRAY(FROM_DT DATE, TO_DT DATE)
RETURNS ARRAY 
AS 
$$
SELECT ARRAY_AGG(DISTINCT LAST_DAY(MY_DATE))
FROM (
  SELECT
    LAST_DAY(DATEADD(MONTH, SEQ4(), FROM_DT)) AS MY_DATE
  FROM TABLE(GENERATOR(ROWCOUNT=>2000000))
  WHERE MY_DATE <= TO_DT
  ORDER BY 1
)
$$;

SELECT LAST_DATES_TO_ARRAY(DATEADD('YEARS', -1, CURRENT_DATE()), CURRENT_DATE()) AS my_array;

 MY_ARRAY
["2018-11-30",
 "2018-12-31",
 "2019-01-31",
 "2019-02-28",
 "2019-03-31",
 "2019-04-30",
 "2019-05-31",
 "2019-06-30",
 "2019-07-31",
 "2019-08-31",
 "2019-09-30",
 "2019-10-31"]
like image 4
Rich Murnane Avatar answered Oct 21 '22 18:10

Rich Murnane