INTERVAL handling in BigQuery's GENERATE_DATE_ARRAY - sql

I'm using GENERATE_DATE_ARRAY to obtain all end-of-month (EOM) dates between two dates. According to the documentation, indeed, GENERATE_DATE_ARRAY supports the MONTH keyword in the INTERVAL part:
SELECT GENERATE_DATE_ARRAY('2020-12-31', '2022-03-31', INTERVAL 1 MONTH)
Unfortunately, as you can see, the result is quite buggy:
It seems that after February, the process get screwed and keeps 28 as the end of month until the final date.
Is there something I'm missing? Or maybe this is a bug?

Consider also below approach (note use of LAST_DAY function)
select last_day(day, month) from
unnest(generate_date_array('2021-01-01', '2022-04-01', interval 1 month)) day

As pointed out by #Jaytiger comment, this may be something expected, although not clearly documented. In the documentation of some date functions is reported (see for example DATE_ADD docs):
Special handling is required for MONTH, QUARTER, and YEAR parts when
the date is at (or near) the last day of the month. If the resulting
month has fewer days than the original date's day, then the resulting
date is the last date of that month.
As a workaround, if you want to obtain the EOM dates, this approach may be used:
SELECT DATE_SUB(day, INTERVAL 1 DAY) FROM
UNNEST(GENERATE_DATE_ARRAY('2021-01-01', '2022-04-01', INTERVAL 1 MONTH)) day
In other words, instead of generating the EOM dates, it is best to generate the start-of-month dates and the subtract a day.
Another approach is to use the method suggested by #Mikhail in his reply.

Related

How to get the first day of the previous month in SQL (BigQuery)

Would any of you know and would like to share the konwledge how to subtract the number of days from the current date (the data is type = DATE) so that I get the first day of the previous month. Here is an example:
Current Date = '2022-10-27'
The date I want = '2022-09-01'
I know how to get the first day of the current month using this:
(CURRENT_DATE() - EXTRACT(DAY FROM CURRENT_DATE()) +1)
BuT I have no idea how to check how many days there were in the previous month and hence get the correct answer.
I though that maybe DATE_TRUNC(CURRENT_DATE() - EXTRACT(DAY FROM CURRENT_DATE())) would work but I'm getting this error:
"No matching signature for function DATE_TRUNC for argument types: DATE"
SO that's clearly not the way. Any suggestions please? :)
Try using a combination of DATE_TRUNC and DATE_SUB as follows:
select current_date() as curr_date,
date_sub(date_trunc(current_date(), MONTH), INTERVAL 1 MONTH) as lm_day_1
It produces the following:

First day of the month

WHERE to_date(smz_loanservicing.as_of_date) = last_day(add_months(current_date, -1))
The above will provide data only if the loanservicing.as_of_date occurs on the very last day of the month.
Last month (May 31 2020) the last day of the month fell on Sunday.
Is there a way to get the the first day of the month and say if this particular date occurs between the first and last day of the month, show the date? Essentially there were no activities on Sunday so the data was missed.
I tried
to_date(smz_loanservicing.as_of_date)
between first_day(add_month(current_date,-1))
and last_day(add_months(current_date, -1))`
However I get syntax error.
You seem to want to check if your date column belongs to the current month.
The syntax you use would work in Oracle, so let me assume this is the database that you are running. I also assume that column as_of_date is of datatype date (or timestamp).
What you ask for should be as simple as:
where
as_of_date >= trunc(current_date, 'mm')
and as_of_date < add_months(trunc(current_date, 'mm'), 1)
Actually, your syntax would also work in Snowflake - and so would the above code.
Note: if as_of_date actually is a string, then you need to_date() to convert it.
You could just truncate the date to the month, then you don’t need the know the first or last day.
where trunc(as_of_date, ‘MM’) = trunc(current_date, ‘MM’)

Best way to break down by weeks in BigQuery

So what I'm looking to do is create a report that shows how many sales a company had on a weekly basis.
So we have a time field called created that looks like this:
2016-04-06 20:58:06 UTC
This field represents when the sale takes place.
Now lets say I wanted to create a report that gives you how many sales you had on a weekly basis. So the above example will fall into something like Week of 2016-04-03 (it doesn't have to exactly say that, I'm just going for the simplest way to do this)
Anyone have any advice? I imagine it involves using the UTEC_TO_xxxxxx functions.
The documentation advises to use standard SQL functions, like DATE_TRUNC():
SELECT DATE_TRUNC(DATE '2019-12-25', WEEK) as week;
you can use WEEK() function - it gives you week number
SELECT WEEK('2016-04-06 20:58:06 UTC')
if you need first day of the week - you can try something like
STRFTIME_UTC_USEC((UTC_USEC_TO_WEEK(TIMESTAMP_TO_USEC(TIMESTAMP('2016-05-02 20:58:06 UTC')), 0)),'%Y-%m-%d')
I had to add parentheses:
SELECT DATE_TRUNC(DATE('2016-04-06 20:58:06 UTC'), WEEK) as week;
This is quite an old question and things have moved on since.
In my case, I found that the old WEEK function is no longer recognised, so I had to instead use the EXTRACT function. The doc for it can be found here.
For me it was enough to just extract the ISOWEEK from the timestamp, which results in the week of the year (the ISOYEAR) as a number.
ISOWEEK: Returns the ISO 8601 week number of the datetime_expression. ISOWEEKs begin on Monday. Return values are in the range [1, 53]. The first ISOWEEK of each ISO year begins on the Monday before the first Thursday of the Gregorian calendar year.
So I did this:
SELECT EXTRACT(ISOWEEK FROM created) as week
And if you want to see the week's last day, rather than the week's number in a year, then:
SELECT last_day(datetime(created), isoweek) as week

Case statement using date intervals

I am trying to create a variable that sums sales in 3 months for each customer after their first purchase in the time series. The code below errors and says I'm missing a parentheses.
sum(case
when merch.trans_dt between min(merch.trans_dt)
and add_date(min(merch.trans_dt), interval 3 month)
then merch.rdswrit_rps_netnet_pur_amt
end) as spend_next3
You can do this by simply using addition, rather than a function: min(merch.trans_dt) + interval 3 month.
However, this may not give you the answer you want. In many cases, such as to_date('1/31/2015','mm/dd/yyyy') + interval '3' month, this will result in ORA-01839: date not valid for month specified.
You're better off using add_months as indicated previously in the comments: add_months(min(merch.trans_dt),3).

Is there a way to search a SQL Query with Month Numbers, and not Month Name?

I am trying to use the actual numerical value for the month on a sql query to pull results. Is there any way to do this without having a function to change the numbers to actual month names, then back to month numbers? The following code works for Names, what works for numbers?
datename(month,(convert(datetime,DTSTAMP)))=
'October'
month,(convert(datetime,DTSTAMP)) should do it, but why on earth are you not storing the data correctly as a datetime to begin with? All that additional conversion stuff to use the dates adds unnecessary load to your server and slows down your application.
Datepart is an alternative to the month command and it is more flexable as you can extract other parts of the date.
DATEPART(mm, convert(datetime,DTSTAMP))
Gets Month Number of Date
CONVERT(VARCHAR(2) ,DTSTAMP ,110)
here, you can search with diff options like:
DATE_SUB(CURDATE(), INTERVAL 0 DAY)
DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
as per your requirement.