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'
]
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.
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".
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.
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/…
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.
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
)
$$;
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"]
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