Calculate due date and exclude working/business days SQL - sql

I would like to calculate a due date.
If the start date is 30/12/2020, I need to count 20 working days from start date and display the date for the 20th working date from start date.
For example if the start date is 30/12/2020 must give me 28/01/2021 (excludes saturdays and sundays and finds the 20th working day from 30/12/2020).
But I am unable to exclude the weekends.
SELECT
DATEADD(DAY,20,CAST(CAST('2020-12-30' AS DATE) AS DATETIME))
-(CASE WHEN DATENAME(dw,'2020-12-30') = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw,'2020-12-30') = 'Saturday' THEN 1 ELSE 0 END) AS DueDate
thanks

Your best pick would be to build a calendar table, with a boolean flag that indicates whether each day is a working day or not. Then you would just do something like:
select dt
from calendar
where dt >= '20201231' and is_working_day = 1
order by dt
offset 19 rows fetch next 1 row only
The way your question is asked, however, one option enumerates the days in a subquery until the count of working days is reached:
declare #dt date = '20201231';
declare #no_days int = 20;
with cte as (
select #dt as dt, #no_days as no_days
union all
select dateadd(day, 1, dt),
case when datename(weekday, dt) in ('Saturday', 'Sunday')
then no_days
else no_days - 1
end
from cte
where no_days > 1
)
select max(dt) as res from cte

If you don't care about holidays, then the 20th working day is exactly 28 days later. So you can use:
dateadd(day, 28, '2020-12-30')
Note: This assumes that the starting date is a working day.

Related

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

query criteria based on current day (sat/sun should return friday's value)

I'm trying to figure out how to return daily results throughout the week while keeping Friday's results visible over the weekend. My current code isn't doing the trick - do I have to mess with arrays?
SELECT ROUND(COUNT(ClosedDate) / 10, 0) * 10 [Previous Day Sales]
FROM PartsSales
WHERE (MONTH(ClosedDate) = MONTH(GETDATE())) AND (YEAR(ClosedDate) = YEAR(GETDATE())) AND (DAY(ClosedDate) = **case** DAY(GETDATE())
when 1 then 1
when 2 then 2
when 3 then 3
when 4 then 4
when 5 then 5
when 6 then 5
when 7 then 5 end
You can use datepart to find the current day of the week (1 = Sunday, 2 = Monday, etc), and then you can use dateadd to go back to Friday's date. If you convert getdate() to a date, then you'll always have the "midnight" at the begining of that day.
dateadd(
day,
case datepart(dw, getdate())
when 1 then -- Sunday
-2
when 7 then -- Saturday
-1
else -- Any other day
0
end,
convert(date, getdate())
)
Is your ClosedDate a datetime datatype? You can make much better use of your indexes by checking for a date range, rather than pulling the dateparts out (using year/month/day). Below is an example with a lot of resused code in the where clause. Of course, if it is just a date datatype, you don't even need a range, since you are calculating the date.
Below is an example. It would be better if you used variables (if you're building this into a stored proc), or perhaps a derived/CTE table. I've kept things verbose for clarity.
SELECT
ROUND(COUNT(ClosedDate) / 10, 0) * 10 [Previous Day Sales]
FROM
PartsSales
WHERE
ClosedDate between
-- Today/Friday's date:
dateadd(
day,
case datepart(dw, getdate())
when 1 then -- Sunday
-2
when 7 then -- Saturday
-1
else -- Any other day
0
end,
convert(date, getdate())
)
and
-- Add 1 day to the "Today/Friday" date.
-- This is the same logic as above, except wrapped in an extra dateadd to add 1 day to it.
dateadd(
day,
1,
dateadd(
day,
case datepart(dw, getdate())
when 1 then -- Sunday
-2
when 7 then -- Saturday
-1
else -- Any other day
0
end,
convert(date, getdate())
)
)

52weeks rolling with running week data

Can someone suggest me how do we consider week to start on Sunday and end on Saturday, while numbering them backwards in a 52 week rolling report like week1, week2.. week52
I want to count my current week as Week1 starting on Sunday, so even if its partial week its still week1 and last week Sunday-Saturday is week2 and so on until 52nd week last year (that would roughly be in September counting backwards). I need this as I am working on a daily report that will look for sales for current week and past 51 (full) weeks. My report should also return any week without sales '0' without skipping it.
Here is a way. Note I created the recursive CTE to populate some dates. You won't have to do this step, and real only need the YourWeekOrder = ... part.
declare #startDate date = dateadd(year,-1,getdate())
declare #endDate date = getdate()
;with cte as(
select #startDate as TheDate
union all
select dateadd(day,1,TheDate)
from cte
where TheDate < #endDate)
select
TheDate
,TheWeekOfYear = datepart(week,TheDate)
,YourWeekOrder = dense_rank() over (order by cast(datepart(year,TheDate) as char(4)) + case when len(datepart(week,TheDate)) = 1 then '0' + cast(datepart(week,TheDate) as char(2)) else cast(datepart(week,TheDate) as char(2)) end desc)
from cte
order by
TheDate
option(maxrecursion 0)
SEE IT IN ACTION HERE

last date of Financial year (I.e 2017-03-31)

Hi please let me know how to extract the last day of Financial year in sql server.my financial year start from 2016-04-01 to 2017-03-31
Closest you can use is End Of Month for that you need to provide one date to that month as below:
select eomonth('2017-03-01')
To get the last day of the financial year for any date, you need to find the last of march if before march, or the last of march next year if after march:
declare #yourdate datetime = getdate();
select case when month(#yourdate) < 4 then CONVERT(datetime,cast(YEAR(#yourdate) as char(4)) + '-03-31' ,120)
else CONVERT(datetime,cast(YEAR(#yourdate) + 1 as char(4)) + '-03-31' ,120)
end as financial_year_end
Edit:
If you want last date derived based on from_date, then use something like this
Rextester Demo
select
case when datepart(mm,from_date) <=3 then
cast(concat(year(from_date),'-03-31') as datetime)
else
dateadd(year,1,cast(concat(year(from_date),'-03-31') as datetime))
end as last_date_fin
from
(select '2017-04-30' as from_date union all
select '2017-01-13') t;
This way from_date between Jan - Mar will give same year's 31st march. Else it will give next year's 31st March.
Previous answer:
http://rextester.com/AXVM26769
If you want to get last day of march for same year as passed, then use
select cast(concat(given_year,'-03-31') as datetime)
from
(select '2017' as given_year) t
If you want to pass 2016 and then get 2017-03-31 then use. You can change the year in derived table and change the output based on that.
select dateadd(year,1,cast(concat(given_year,'-03-31') as datetime))
from
(select '2016' as given_year) t;
This Code will work to find the last date of Financial Year.
For Previous Year case matches and 'THEN' part will Execute and for current year 'ELSE'
part will execute.
select CASE WHEN (MONTH(GETDATE())) <= 3
THEN convert(varchar(4), YEAR(GETDATE())-1) + '-' + '03-31'
ELSE convert(varchar(4),YEAR(GETDATE()))+ '-' + '03-31'
end
> LastDayOfYearFY] =
> eomonth( dateadd(month, 5,
> dateadd(year, datepart(year, (dateadd(month, 6, [date])) ) -1900, 0)))
Idea extension taken from return-first-day-of-financial-year
You can select all the dates order them descendant and take the first one.
SELECT date
FROM table
ORDER BY date desc
LIMIT 1;

SQL Server : is there a way for me to get weeks per month using Month and Year?

I'm not really good when it comes to database...
I'm wondering if it is possible to get the weeks of a certain month and year..
For example: 1 (January) = month and 2016 = year
Desired result will be:
week 1
week 2
week 3
week 4
week 5
This is what I have tried so far...
declare #date datetime = '01/01/2016'
select datepart(day, datediff(day, 0, #date) / 7 * 7) / 7 + 1
This only returns the total of the weeks which is 5.
declare #MonthStart datetime
-- Find first day of current month
set #MonthStart = dateadd(mm,datediff(mm,0,getdate()),0)
select
Week,
WeekStart = dateadd(dd,(Week-1)*7,#MonthStart)
from
( -- Week numbers
select Week = 1 union all select 2 union all
select 3 union all select 4 union all select 5
) a
where
-- Necessary to limit to 4 weeks for Feb in non-leap year
datepart(mm,dateadd(dd,(Week-1)*7,#MonthStart)) =
datepart(mm,#MonthStart)
Got the answer in the link: http://www.sqlservercentral.com/Forums/Topic1328013-391-1.aspx
Here is one way to approach this:
A month has a minimum of 29 or more days, and a max of 31 or less. Meaning there are almost always 5 weeks a month, with the exception of a non-leap year's feburary, and in those cases, 4 weeks a month.
You can refer to this to find out which years are "leap".
Check for leap year
Hope this helps!
The following code will allow you to select a start and end date, and output one row per week, with numbered weeks, between those dates:
declare #start date = '1/1/2016'
declare #end date = '5/1/2016'
;with cte as (select #start date
, datename(month, #start) as month
union all
select dateadd(dd, 7, date)
, datename(month, dateadd(dd, 7, date))
from CTE
where date <= #end
)
select *, 'week '
+ cast(row_number() over (partition by month order by date) as varchar(1))
from CTE
order by date