SQL Query for finding number of days in a month of year 2022 - sql

Need this table as output
DECLARE #ADate DATETIME
SET #ADate = GETDATE()
SELECT DAY(EOMONTH(#ADate)) AS DaysInMonth
Output: Jan 31 (I got only one month’s output. I need all the months in 2022 and their days)

You can do something like this:
WITH months AS
(
SELECT 1 AS MONTH
UNION ALL
SELECT MONTH + 1
FROM months
WHERE MONTH < 12
)
SELECT CAST(DATENAME(month, CONCAT("2022-" , months.MONTH, "-01")) AS CHAR(3)) AS 'MONTH' , DAY(EOMONTH(CONCAT("2022-" , months.MONTH, "-01"))) as DAY FROM months
Output:
MONTH
DAY
Jan
31
Feb
28
Mar
31
Apr
30
May
31
Jun
30
Jul
31
Aug
31
Sep
30
Oct
31
Nov
30
Dec
31
Create a row generator from 1 to 12 using WITH ,after that is just formating the output
You can view the result here: https://onecompiler.com/sqlserver/3yurzpsnm

Related

Select row with most recent date per location and increment recent date by 1 for each row by location using MariaDB

I have a table of location which has 'Date column'. I have to find recent date by each group of locationID for e.g. locationID 1 has most recent date '31 May 2022'. After finding recent date from the group of locationID I have to add 14 days in that recent date and store it in NewDate column. and add + 1 in that new date for other row for that group of locationID.
My table is:
id locationID Date NewDate
1 1 31 May 2022
2 1 16 May 2022
3 1 28 Apr 2021
4 2 29 Mar 2022
5 2 22 Feb 2022
6 3 14 Jun 2022
7 3 27 Oct 2021
8 4 01 Feb 2022
9 4 04 May 2022
10 4 14 Jun 2021
11 5 01 Jun 2022
12 5 29 May 2022
13 5 20 Sep 2022
14 5 11 Aug 2022
15 5 03 Aug 2022
Answer should be as below:
For e.g. for locationID = 1
id locationID Date NewDate
1 1 31 May 2022 14 Jun 2022 // Recent Date + 14 Days - 31 May + 14 Days
2 1 16 May 2022 15 Jun 2022 // Recent Date + 15 Days - 31 May + 15 Days
3 1 28 Apr 2021 16 Jun 2022 // Recent Date + 16 Days - 31 May + 16 Days
I have come across few similar post and found recent date like this:
SELECT L.*
FROM Locations L
INNER JOIN
(SELECT locationID, MAX(Date) AS MAXdate
FROM Locations
GROUP BY locationID) groupedL
ON L.locationID = groupedL.locationID
AND L.Date = groupedL.MAXdate
using above code I am able to find recent date per location but how do I add and increment required days and store it to NewDate column ? I am new to MariaDB, please suggest similar post link, any reference documents or blogs. Should I make some function to perform this logic and call the function to store required dates in NewDate column? I am not sure please suggest. Thank you.
RESULT SHOULD LOOK LIKE BELOW:
id locationID Date NewDate
1 1 31 May 2022 14 Jun 2022 // Recent Date for locationid 1 + 14 Days - 31 May + 14 Days
2 1 16 May 2022 15 Jun 2022 // Recent Date for locationid 1 + 15 Days - 31 May + 15 Days
3 1 28 Apr 2021 16 Jun 2022 // Recent Date for locationid 1 + 16 Days - 31 May + 16 Days
4 2 29 Mar 2022 12 APR 2022 // Recent Date for locationid 2 + 14 Days
5 2 22 Feb 2022 13 APR 2022 // Recent Date for locationid 2 + 15 Days
6 3 14 Jun 2022 28 JUN 2022 // Recent Date for locationid 3 + 14 Days
7 3 27 Oct 2021 29 JUN 2022 // Recent Date for locationid 3 + 15 Days
8 4 01 Feb 2022 18 MAY 2022 // Recent Date for locationid 4 + 14 Days
9 4 04 May 2022 19 MAY 2022 // Recent Date for locationid 4 + 15 Days
10 4 14 Jun 2021 20 MAY 2022 // Recent Date for locationid 4 + 16 Days
11 5 01 Jun 2022 04 OCT 2022 // Recent Date for locationid 5 + 14 Days
12 5 29 May 2022 05 OCT 2022 // Recent Date for locationid 5 + 15 Days
13 5 20 Sep 2022 06 OCT 2022 // Recent Date for locationid 5 + 16 Days
14 5 11 Aug 2022 07 OCT 2022 // Recent Date for locationid 5 + 17 Days
15 5 03 Aug 2022 08 OCT 2022 // Recent Date for locationid 5 + 18 Days
You can use a cte:
with cte as (
select l1.*, l2.m, (select sum(l4.id < l1.id and l4.locationid = l1.locationid) from locations l4) inc from locations l1
join (select l3.locationid, max(l3.dt) m from locations l3 group by l3.locationid) l2 on l1.locationid = l2.locationid
)
select c.id, c.locationid, c.dt, c.m + interval 14 + c.inc day from cte c
You could use analytic window functions and update the original table by joining to a sub-query (works for MariaDB):
update t
join (
select Id,
Date_Add(First_Value(date) over(partition by locationId order by date desc),
interval (13 + row_number() over(partition by locationId order by date desc)) day
) NewDate
from t
)nd on t.id = nd.id
set t.Newdate = nd.NewDate;
See DB<>Fiddle example

big query SQL - repeatedly/recursively change a row's column in the select statement based on the values in previous row

I have table like below
customer
date
end date
1
jan 1 2021
jan 30 2021
1
jan 2 2021
jan 31 2021
1
jan 3 2021
feb 1 2021
1
jan 27 2021
feb 26 2021
1
feb 3 2021
mar 5 2021
2
jan 2 2021
jan 31 2021
2
jan 10 2021
feb 9 2021
2
feb 10 2021
mar 12 2021
Now, I wanted to update the value in the 'end date' column of a row based on the values in the previous row 'end date' and the current row 'date'.
Say if the date in current row < end date of the previous row, I wanted to update the end date of the current row = (end date of the previous row).
I Wanted to do this repeated for all the rows (grouped by customer).
I want the output as below. Just need it in the select statement instead of a updating/inserting in a table.
Note - in below as the second row(end date) is updated with the value in the first row (jan 30 2021), now the third row value (jan 3 2021) is evaluated against the updated value in the second row (which is jan 30 2021) but not with the second row value before update (jan 31 2021).
customer
date
end date
1
jan 1 2021
jan 30 2021
1
jan 2 2021
jan 30 2021 [updated because current date < previous end date]
1
jan 3 2021
jan 30 2021[updated because current date < previous end date]
1
jan 27 2021
jan 30 2021 [updated because current date < previous end date]
1
feb 3 2021
mar 5 2021
2
jan 2 2021
jan 31 2021
2
jan 10 2021
jan 31 2021[updated because current date < previous end date]
2
feb 10 2021
mar 12 2021
I think I should go this way. I use the datasource twice just to get the way its needed to perform the operation without updating or inserting into the table.
input table:
1|2021-01-01|2021-01-30
1|2021-01-02|2021-01-31
1|2021-01-03|2021-02-01
1|2021-01-27|2021-02-26
1|2021-02-03|2021-03-05
2|2021-01-02|2021-01-31
2|2021-01-10|2021-02-09
2|2021-02-10|2021-03-12
code:
with num_raw_data as (
SELECT row_number() over(partition by customer)as num, customer,date_init,date_end
FROM `project-id.data-set.table`
), analyzed_data as(
select r.num,
r.customer,
r.date_init,
r.date_end,
case when date_init<(select date_end from num_raw_data where num=r.num-1 and customer=r.customer and EXTRACT(month FROM r.date_init)=EXTRACT(month FROM date_init)) then 1 else 0 end validation
from num_raw_data r
)
select customer,
date_init,
case when validation !=0 then (select MIN(date_end) from analyzed_data where validation=0 and customer=ad.customer and date_init<ad.date_end) else date_end end as date_end
from analyzed_data ad
order by customer,num
output:
1|2021-01-01|2021-01-30
1|2021-01-02|2021-01-30
1|2021-01-03|2021-01-30
1|2021-01-27|2021-01-30
1|2021-02-03|2021-03-05
2|2021-01-02|2021-01-31
2|2021-01-10|2021-01-31
2|2021-02-10|2021-03-12
Using column validation from analyzed_data to get to know where I should be looking for changes. I'm not sure if its fast (probably not) but it works for the scenario you bring in your question.

Showing data order from Monday-Sunday full week only and hide non-full week data

sorry if I'm shooting newbie questions here.
I want to create a weekly report, but for this weekly report, I want full data from Monday to Sunday
Condition:
Last 4 weeks only
Showing full week (Monday - Sunday)
Hide the result if it's not full week
If i use getdate -14, if I access the data on Wednesday, they will start counting last week from Wednesday 2 weeks ago instead of last Monday. Meanwhile, I want the report to show full week only.
Can anyone share how to do that in SQL?
Here I provide sample data:
Column name = DATE -- Column name: TOTAL_PERSON
- Fri, 1 Jun 2018 -- 10
- Sat, 2 Jun 2018 -- 4
- Sun, 3 Jun 2018 -- 12
- Mon, 4 Jun 2018 -- 15
- Tue, 5 Jun 2018 -- 10
- Wed, 6 Jun 2018 -- 3
- Thu, 7 Jun 2018 -- 1
- Fri, 8 Jun 2018 -- 13
- Sat, 9 Jun 2018 -- 9
- Sun, 10 Jun 2018 -- 23
- Mon, 11 Jun 2018 -- 5
- Tue, 12 Jun 2018 -- 3
- Wed, 13 Jun 2018 -- 1
- Thu, 14 Jun 2018 -- (TODAY)
In this case, if I am accessing on Thu 6 Jun 2018 I want to get TOTAL PERSON data from Mon, 4 Jun 2018 to Sun, 10 Jun 2018 only and not showing data from the rest since the week is not full.
Can anyone help me how to do that?
Thanks a lot!
I think you want:
where datediff(week, date, getdate()) <= 2
This counts the number of week boundaries between two dates, so it returns an entire week.
For MySQL, you can use such a select:
SELECT * FROM `myDB` WHERE `Date`
BETWEEN DATE_SUB(NOW()-INTERVAL DATE_FORMAT(CURRENT_DATE, '%w') DAY, INTERVAL 28 DAY)
AND NOW()- INTERVAL DATE_FORMAT(CURRENT_DATE, '%w') DAY
This uses the capability to transform the current day of this week into a number and substract this to get the last Sunday. from there, we select an intervall of 28 days.
(Only testet with 14 days and a very limited test-dataset, but should work)

getting first day and last day of a quarter and 2 quarters back for a date

how to get first day and last day of a quarter for a date?
and also first day and last day of 2 quarters back for a date in Hive or sql
for example for Feb 03 2014 first day and last day of the quarter will be
Jan 01 2014 and Mar 31 2014
and for the same date first and last day of 2 quarters back will be Jul 01 2013 and Sep 31 2013
You can accomplish this in the following way (not too fancy, but there is no direct way). To make it simpler, I just concatenated both output dates
-- before Hive 1.3
select
case
when ceil(month(mydate)/ 3.0) = 1 then concat("Jan 01 ",year(mydate),"|","Mar 31 ",year(mydate))
when ceil(month(mydate)/ 3.0) = 2 then then concat("Apr 01 ",year(mydate),"|","Jun 30 ",year(mydate))
when ceil(month(mydate)/ 3.0) = 3 then then concat("Jul 01 ",year(mydate),"|","Sep 30 ",year(mydate))
when ceil(month(mydate)/ 3.0) = 4 then then concat("Oct 01 ",year(mydate),"|","Dec 31 ",year(mydate))
else
null
end,
ceil(month(mydate)) as quarter
from (
select
from_unixtime(unix_timestamp('Feb 03 2014' , 'MMM dd yyyy')) as mydate
) t;
--Hive 1.3 or higher
select
case
when quarter(mydate) = 1 then concat("Jan 01 ",year(mydate),"|","Mar 31 ",year(mydate))
when quarter(mydate) = 2 then then concat("Apr 01 ",year(mydate),"|","Jun 30 ",year(mydate))
when quarter(mydate) = 3 then then concat("Jul 01 ",year(mydate),"|","Sep 30 ",year(mydate))
when quarter(mydate) = 4 then then concat("Oct 01 ",year(mydate),"|","Dec 31 ",year(mydate))
else
null
end,
ceil(month(mydate)) as quarter
from (
select
from_unixtime(unix_timestamp('Feb 03 2014' , 'MMM dd yyyy')) as mydate
) t;
just replace the hardcoded date for your column in the select in the inner query

Adding set lists of future dates to rows in a SQL query

So I am doing a cohort analysis for customers, where a cohort is a group of people who started using the product in the same month. I then keep track of each cohort's total use for every subsequent month up till present time.
For example, the first "cohort month" is January 2012, then I have "use months" January 12, Feb 12, March 12, ..., March 17(current month). One column is "cohort month", and another is "use month". This process repeats for every subsequent cohort month. The table looks like:
Jan 12 | Jan 12
Jan 12 | Feb 12
...
Jan 12 | Mar 17
Feb 12 | Feb 12
Feb 12 | Mar 12
...
Feb 12 | Mar 17
...
Feb 17 | Feb 17
Feb 17 | Mar 17
Mar 17 | Mar 17
The problem arises because I want to do forecasting for one year out for both existing and future cohorts.
That means for the Jan 12 cohort, I want to do prediction for April 17 to Mar 18.
I also want to do predictions for the April 17 cohort (which doesn't exist yet) from April 17 to Mar 18. And so on till predictions for the Mar 18 cohort in Mar 18.
I can handle the predictions, don't worry about that.
My issue is that I cannot figure out how to add in this list of (April 17 .. Mar 17) in the "use month" column before every cohort switches.
I also need to add in cohorts April 17 to Mar 18, and have the applicable parts of this list of (April 17 ... Mar 17) for each of these future cohorts.
So I want the table to look like:
Jan 12 | Jan 12
Jan 12 | Feb 12
...
Jan 12 | Mar 17
Jan 12 | Apr 17
..
Jan 12 | Mar 18
Feb 12 | Feb 12
Feb 12 | Mar 12
...
Feb 12 | Mar 17
Feb 12 | Apr 17
...
Feb 12 | Mar 18
...
...
Feb 17 | Feb 17
Feb 17 | Mar 17
...
Feb 17 | Mar 18
Mar 17 | Mar 17
...
Mar 17 | Mar 18
I know the first solution to come to mind is to do a create a list of all dates Jan 12 to Mar 18, cross join it to itself, and then left outer join to the current table I have (where cohort / use months range from Jan 12 to Mar 17). However, this is not scalable.
Is there a way I can just iteratively add in this list of the months of the next year?
I am using HP Vertica, could use Presto or Hive if absolutely necessary
I think you should use the query here below to create a temporary table out of nothing, and join it with the rest of your query. You can't do anything in a procedural manner in SQL, I'm afraid. You won't be able to get away without a CROSS JOIN. But here, you limit the CROSS JOIN to the generation of the first-of-month pairs that you need.
Here goes:
WITH
-- create a list of integers from 0 to 100 using the TIMESERIES clause
i(i) AS (
SELECT dt::DATE - '2000-01-01'::DATE
FROM (
SELECT '2000-01-01'::DATE + 0
UNION ALL SELECT '2000-01-01'::DATE + 100
) d(d)
TIMESERIES dt AS '1 day' OVER(ORDER BY d::TIMESTAMP)
)
,
-- limits are Jan-2012 to the first of the current month plus one year
month_limits(month_limit) AS (
SELECT '2012-01-01'::DATE
UNION ALL SELECT ADD_MONTHS(TRUNC(CURRENT_DATE,'MONTH'),12)
)
-- create the list of possible months as a CROSS JOIN of the i table
-- containing the integers and the month_limits table, using ADD_MONTHS()
-- and the smallest and greatest month of the month limits
,month_list AS (
SELECT
ADD_MONTHS(MIN(month_limit),i) AS month_first
FROM month_limits CROSS JOIN i
GROUP BY i
HAVING ADD_MONTHS(MIN(month_limit),i) <= (
SELECT MAX(month_limit) FROM month_limits
)
)
-- finally, CROSS JOIN the obtained month list with itself with the
-- filters needed.
SELECT
cohort.month_first AS cohort_month
, use.month_first AS use_month
FROM month_list AS cohort
CROSS JOIN month_list AS use
WHERE use.month_first >= cohort.month_first
ORDER BY 1,2
;