Case statement using date intervals - sql

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).

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:

INTERVAL handling in BigQuery's GENERATE_DATE_ARRAY

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.

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’)

How to round up a month-date based on certain parameters

I need to round up a month-date based on certain parameters. For example: If I have a parameter where if a day in a given month is between the 6th and the 4th of the next month, I need my query to return the next months date. Is there a way to round up the month given these parameters without hard coding case whens for every single month ever?
SELECT case when date_trunc('day',li.created_at between '2019-03-06 00:00:00' and '2019-04-06 00:00:00' then '2019-04-01' end)
FROM line_items li
If you want the beginning of the month, but offset by 4 days, you can use date_trunc() and subtract some number of days (or add some number of days). You seem to want something like this:
select dateadd(month, 1, date_trunc('month', li.created_at - interval '4 day'))
Another approach is to create a canonical "dates" table that precomputes the mapping from a given date to a new date using your rounding scheme. The mapping could be done outside of redshift in a script and the table loaded in (or within redshift using a user defined function).

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.