Find out last month's data when rolling into a new year - sql

Currently, I am using this code to look at the previous month's data for quicksight in Amazon's Athena (this first part works*):
SELECT month, count(1)
FROM table1
WHERE CAST(EXTRACT(month from now()) - 1 as VARCHAR(2)) = month
GROUP BY month
The challenge is how to ensure that this code will work once we roll over into a new year? I currently have
SELECT month, count(1)
FROM table1
WHERE CASE WHEN( month = '1' THEN month = '13'
ELSE month
END)
CAST(EXTRACT(month from now()) - 1 as VARCHAR(2)) = month
GROUP BY month
To clarify, month was input as a string, hence the CAST as VARCHAR(2) to get "01" through "12".
My thought process behind this was that if month = '01', then it reads it as '13', then extracts '1', equaling '12'. But not sure if that will work

You can use the date_add function to subtract one month from today:
SELECT DATE_ADD('month', -1, NOW())
Alternatively you can subtract an interval of one month to achieve the same results:
SELECT NOW() - INTERVAL '1' MONTH
In both cases you can then use MONTH(…) or EXTRACT(MONTH FROM …) to get the month number.

You seem to want:
where month = extract(month from now()) - 1 or
(extract(month from now()) = 1 and month = 12)

Related

Get data of last Month day by day in oracle sql

I want to get data from last month day by day, I can get the last 30 days but I just want the month as it may be less or more than 30 days,
this is the query for getting the last 30 days
SELECT Trunc(timestamp),
Count(*)
FROM table1
WHERE Trunc(timestamp) > Trunc(sysdate - 30)
GROUP BY Trunc(timestamp)
ORDER BY 1;
Also, I am using it in a shell script if I can make a variable in the script and put it the query
To get data from the start of the current month until today:
SELECT TRUNC(timestamp) AS day,
COUNT(*)
FROM table1
WHERE timestamp >= TRUNC(SYSDATE, 'MM')
AND timestamp < TRUNC(SYSDATE) + INTERVAL '1' DAY
GROUP BY TRUNC(timestamp)
ORDER BY day
To get data from the same day last month until today:
SELECT TRUNC(timestamp) AS day,
COUNT(*)
FROM table1
WHERE timestamp >= ADD_MONTHS(TRUNC(SYSDATE), -1)
AND timestamp < TRUNC(SYSDATE) + INTERVAL '1' DAY
GROUP BY TRUNC(timestamp)
ORDER BY day
db<>fiddle here

Find the number of days in a given month in sqlite3

I am trying to calculate wages data. Is there a way to calculate the number of days in a given month in sqlite3
There are multiple ways to do it, but you can use JULIANDAY to calculate the difference in days between the date in a month and the current date, which should give you the number of days of the current month.
For example to calculate the number of days in the month that contains the date 2010-05-31;
SELECT JULIANDAY('2010-05-31', '+1 month') - JULIANDAY('2010-05-31') days_of_month
> 31
An SQLfiddle to test with.
Use the DATE function to get from some date to its month's last day, e.g. from '2021-06-05' to '2021-06-30'. Then use STRFTIME to extract that day ('30' in the example). Then cast to INTEGER to get from the day string to a number ('30' -> 30).
SELECT
CAST(
STRFTIME(
'%d',
DATE(
'2021-06-05',
'start of month',
'+1 month',
'-1 day'
)
) AS INTEGER
);
Demo: https://dbfiddle.uk/?rdbms=sqlite_3.27&fiddle=45d8620632c831d554b435b501f98912
Assuming that you have the year and the month as a number, you can do it with strftime():
SELECT strftime('%d', '2021' || '-' || printf('%02d', ?) || '-01', '1 month', '-1 day') days
Replace '2021' with the year that you want and ? with the month number.
See the demo.

How to get from a date column the last date of the previous month?

I have two date columns, which takes into account only working days. A_date and E_date.
E_date is calculated adding +2 days to A_date, because that's the request
The problem is that if the day of A_date is 30th or 31st of the month, then E_date date needs to be the last day of the current month, and not the first or second working day of the next month.
i have tried eomonth function but that does not work because it would need a explicit date.
Do you have any idea how to solve it?
You can use EOMONTH() in SQLServer to get the last day of the month.
Example:
EOMONTH(A_date)
SELECT CASE WHEN dateadd(month,1+datediff(month,0,A_date),-1)< DATEADD(day, 2, A_date) THEN dateadd(month,1+datediff(month,0,A_date),-1) ELSE DATEADD(day, 2, A_date) END E_date
FOR input of 2019/09/30 output is 2019-09-30 00:00:00.000
I'm not sure what your question is. What I've understood so far is that you want the last date of the month in case when adding two days to A_Date jumps to the next month.
Why don't you use CASE WHEN and compare out the months, this way :
DECLARE #A_Date date = '2019/09/30';
DECLARE #A_Date_Month int = 0;
DECLARE #E_Date_Month int = 0;
SELECT #A_Date_Month = Month(Cast(#A_Date AS datetime));
SELECT #E_Date_Month = Month(DATEADD(day, 2, #A_Date));
SELECT CASE
WHEN #A_Date_Month = #E_Date_Month
THEN DATEADD(day, 2, #A_Date)
ELSE EOMONTH(#A_Date) END AS OUTPUTValue
Try out the above set and do let me know if it resolves your issue!
How to get from a date column the last date of the previous month?
It depends on your RDBMS, so let's take the opportunity to make a generic answer:
In Oracle:
LAST_DAY(ADD_MONTHS(mydate ,-1))
In MySQL:
LAST_DAY(mydate - INTERVAL 1 MONTH)
In SQL Server:
DATEADD(MONTH, DATEDIFF(MONTH, -1, mydate )-1, -1)
-- or simply:
EOMONTH(DATEADD(Month, -1, mydate ))
In Postgres:
date_trunc('month', now())::mydate - 1
have two date columns, which takes into account only working days. A_date and E_date. E_date is calculated adding +2 days to A_date, because that's the request
I would simply do:
(case when dateadd(day, 2, a_date) < eomonth(a_date)
then dateadd(day, 2, a_date)
else eomonth(a_date)
end) as e_date
If you truly want this only on the 30th or 31st of any given month and not the last 2 days of any month (since obviously not every month has 31 days) --
select A_date
,case when day(A_date) >= 30
then eomonth(A_date)
else dateadd("dd",2,A_date)
end as E_date
Other answers work for "last 2 days of any month".

Extract Month in sql and adding 1

If I add 1 to extract(month from date), then does the result become 13 or 1 (January of next year)
I have the below code:
(extract(day from sysdate) >=1 and extract(month from sysdate)=12) and (targstartdate >= to_date(((extract(month from sysdate))|| '-1-' || (extract(year from sysdate)+1)) , 'mm-dd-yyyy') and targstartdate <= to_date(((extract(month from sysdate)+1)|| '-1-' ||(extract(year from sysdate)+1)) , 'mm-dd-yyyy')
You can use MOD
MOD(extract(month from sysdate)+1,12) + 1
If you are trying to get the month number of the next month, flip your logic. Instead of extracting the month number and adding 1, add one month to the date then extract the month. See the difference below. The second adds one month, then extracts the month of 1 (for January).
select extract( month from to_date('12/15/2017','MM/DD/YYYY')) + 1 from dual
union all
select extract (month from ADD_MONTHS(to_date('12/15/2017','MM/DD/YYYY'),1)) from dual;

Select data with a rolling date criteria

The below query returns a distinct count of 'members' for a given month and brand (see image below).
select to_char(transaction_date, 'YYYY-MM') as month, brand,
count(distinct UNIQUE_MEM_ID) as distinct_count
from source.table
group by to_char(transaction_date, 'YYYY-MM'), brand;
The data is collected with a 15 day lag after the month closes (meaning September 2016 MONTHLY data won't be 100% until October 15). I am only concerned with monthly data.
The query I would like to build: Until the 15th of this month (October), last month's data (September) should reflect August's data. The current partial month (October) should default to the prior month and thus also to the above logic.
After the 15th of this month, last month's data (September) is now 100% and thus September should reflect September (and October will reflect September until November 15th, and so on).
The current partial month will always = the prior month. The complexity of the query is how to calc prior month.
This query will be ran on a rolling basis so needs to be dynamic.
To be clear, I am trying to build a query where distinct_count for the prior month (until end of current month + 15 days) should reflect (current month - 2) value (for each respective brand). After 15 days of the close of the month, prior month = (current month - 1).
Partial current month defaults to prior month's data. The 15 day value should be variable/modifiable.
First, simplify the query to:
select to_char(transaction_date, 'YYYY-MM') as month, brand,
count(distinct members) as distinct_count
from source.table
group by members, to_char(transaction_date, 'YYYY-MM'), brand;
Then, you are going to have a problem. The problem is that one row (say from Aug 20th) needs to go into two groups. A simple group by won't handle this. So, let's use union all. I think the result is something like this:
select date_trunc('month', transaction_date) as month, brand,
count(distinct members) as distinct_count
from source.table
where (date_trunc('month', transaction_date) < date_trunc('month' current_date) - interval '1 month') or
(day(current_date) > 15 and date_trunc('month', transaction_date) = date_trunc('month' current_date) - interval '1 month')
group by date_trunc('month', transaction_date), brand
union all
select date_trunc('month' current_date) - interval '1 month' as month, brand,
count(distinct members) as distinct_count
from source.table
where (day(current_date) < 15 and date_trunc('month', transaction_date) = date_trunc('month' current_date) - interval '1 month')
group by brand;
Since you already have a working query, I concentrate on the subselect. The condition you can use here is CASE, especially "Searched CASE"
case
when extract(day from current_date) < 15 then
extract(month from current_date - interval '2 months')
else
extract(month from current_date - interval '1 month')
end case
This may be used as part of a where clause, for example.
Here is some sudo code to get the begin date and the end date for your interval.
Begin date:
date DATE_TRUNC('month', CURRENT_DATE - integer 15) - interval '1 month'
This will return the current month only after the 15th day, from there you can subtract a full month to get your starting point.
End Date:
To calculate this, grab the begin date, plus a month, minus a day.
If the source table is partitioned by transaction_date, this syntax (not masking transaction_date with expression) enables partitions eliminatation.
select to_char(transaction_date, 'YYYY-MM') as month
,count (distinct members) as distinct_count
,brand as brand
FROM source.table
where transaction_date between date_trunc('month', current_date) - case when extract (day from current_date) >= 15 then 1 else 2 end * interval '1' month
and date_trunc('month', current_date) - case when extract (day from current_date) >= 15 then 0 else 1 end * interval '1' month - interval '1' day
group by to_char(transaction_date, 'YYYY-MM')
,brand
;