Reputation: 209
I am stuck with a SQL query.
I am trying to calculate two different things in a same query:
Let's say for November (as on 11/9/2018)
no.of business days no. of business days passed
22 7
I tried like this :
WITH cteAllDates AS
(
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '10/01/2018'
SET @EndDate = '10/31/2018'
SELECT
(DATEDIFF(dd, @StartDate, @EndDate) + 1)
- (DATEDIFF(wk, @StartDate, @EndDate) * 2)
- (CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) AS x
) AS y
SELECT x
FROM cteAllDates
I would like to create a virtual table so that I can use these fields in my complete query. And if its possible I can do this with GETDATE()
and not to declare dates every time.
Upvotes: 0
Views: 639
Reputation: 2814
Since you want to do it in a CTE, and based on the earlier answer you found on SO, here is a version that does it all for the current month without needing to define start and end dates:
EDIT: To create a holiday table
First, create a holiday table. Don't do this every time, make it a persistent table, and keep it filled up with all holidays you need - easter, xmas etc.
create table holidays(holiday date)
insert holidays values ('2018-09-23'),('2018-09-24')
Now the query, including the check for number of holidays between the dates
;with dates as(
select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
convert(date,getdate()) as today
)
,holidaycount as (
select count(*) as holidaysinmonth,
sum(case when holiday<=today then 1 else 0 end) as holidaystodate
from dates
join holidays on holiday between startofmonth and endofmonth
)
,daycounts as(
select dates.*,
(DATEDIFF(dd, startofmonth, endofmonth) + 1)
-(DATEDIFF(wk, startofmonth, endofmonth) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END)
-isnull(holidaysinmonth,0) as wkdaysinmonth,
(DATEDIFF(dd, startofmonth, today) + 1)
-(DATEDIFF(wk, startofmonth, today) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END)
-isnull(holidaystodate,0) as wkdaystodate
from dates
cross join holidaycount
)
select * from daycounts
EDIT: If you cant create a temp table, add this as an additional CTE before the holidaycount one like so:
,holidays as (
select holiday from (values ('2018-11-23'),('2018-11-24')) t(holiday)
)
,holidaycount as (
Upvotes: 1
Reputation: 46249
You can try to use cte recursive make a calendar table, then use condition aggregate function to get your result.
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1));
SET @EndDate = DATEADD(DAY, 1, EOMONTH(GETDATE()));
;WITH CTE AS (
select @StartDate startdt,@EndDate enddt
UNION ALL
SELECT DATEADD (day ,1 , startdt) , @EndDate
FROM CTE
WHERE DATEADD (day,1,startdt) <= @EndDate
)
select SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') THEN 1 END) 'no.of business days',
SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') AND GETDATE() >= startdt THEN 1 END) 'no. of business days passed'
FROM CTE
Result
no.of business days no. of business days passed
22 7
Upvotes: 0