I have a table with start and end dates in. My goal is to have a table that has grouped these dates into how many days the period spans. I thought I had the solution with a simple SQL statement (MS SQL Server 2005) but I want to exclude weekends.
SELECT DATEDIFF(D, StartDate, EndDate)+1 AS Days,
COUNT(ID) as Count
FROM myDateTable
GROUP BY DATEDIFF(D, StartDate, EndDate)
This gives a record set of:
Days Count
1 4
2 2
4 1
7 2
Is this possible to exclude the weekends in the SQL statement and if not can it be done using ASP and a array perhaps?
Well then, using Sql Server 2005, you can try something like
DECLARE #Table TABLE(
ID INT,
StartDate DATETIME,
EndDate DATETIME
)
INSERT INTO #Table (ID,StartDate,EndDate) SELECT 1, '25 Jan 2009', '31 Jan 2009'
INSERT INTO #Table (ID,StartDate,EndDate) SELECT 2, '01 Jan 2009', '07 Jan 2009'
INSERT INTO #Table (ID,StartDate,EndDate) SELECT 3, '01 Jan 2009', '14 Jan 2009'
DECLARE #MinDate DATETIME,
#MaxDate DATETIME
SELECT #MinDate = MIN(StartDate) ,
#MaxDate = MAX(EndDate)
FROM #Table
--Create a temp result set between the Min and Max dates, with all dates, and their weekday names
;WITH DayValues AS(
SELECT #MinDate DateVal,
DATENAME(dw, #MinDate) DateValName
UNION ALL
SELECT DateVal + 1,
DATENAME(dw, DateVal + 1) DateValName
FROM DayValues
WHERE DateVal + 1 <= #MaxDate
),
--select the count of days for each StartDate and EndDate pair, excluding Saturdays and Sundays
DateCounts AS(
SELECT ID,
(
SELECT COUNT(1)
FROM DayValues
WHERE DateVal BETWEEN StartDate AND EndDate
AND DateValName NOT IN ('Saturday', 'Sunday')
) DateCount
FROM #Table
)
--Now group and count
SELECT DateCount,
COUNT(ID) TotalCount
FROM DateCounts
GROUP BY DateCount
OPTION (MAXRECURSION 0)
Output
DateCount TotalCount
----------- -----------
5 2
10 1
EDIT: Brief Explenation
You need to determine the number of days between (and including) 2 dates, that are not weekends.
So using a CTE, I create a temporary result set of dates ebwteen the Min and Max dates, and their Weekday Name (eg Monday, Tuesday... Sunday).
Then, for each of your date pairs, I count the number of entries that does not correspond to Saturday and Sunday.
Here's an ASP function that counts days weekdays between two dates.
<%
Dim StartDate, EndDate
StartDate = CDate("1/1/2010")
EndDate = CDate("2/1/2010")
Response.Write(WeekDayCount(StartDate, EndDate))
Function WeekDayCount(StartDate, EndDate)
dim tempDate, dayCount
tempDate = StartDate
dayCount = 0
'Step forward one day, counting non-week days
While tempDate <> EndDate
'The 1 and 7 might need to be tweaked depending on the locale of your
'server. 1 = Sunday, 7 = Saturday
If DatePart("w", tempDate) <> 1 And DatePart("w", tempDate) <> 7 Then
dayCount = dayCount + 1
End If
tempDate = DateAdd("d", 1, tempDate)
Wend
WeekDayCount = dayCount
End Function
%>
Have a look at ##DATEFIRST,
and look a this;
SELECT DATEPART(DW,GETDATE()).
You should be able to run a query WHERE the 'DW' is not equal to the weekend numbers.
Related
How can I get the date of specific day ? Like if I have Thursday or month number ?
If I give 12 for instance I want to get the date of 12th day of this month. Or if I give 'Sun' or 'Sat' is it possible to get the dates of these days ?
DATEFROMPARTS function can construct a date from day, month and year.
DATEPARTS does the opposite - gives you the day, month, year, hour, etc. of a date. Or you can use functions like YEAR, MONTH and DAY.
You can deconstruct the value returned by GETDATE function and construct whatever date you want. Here is for example how to get the date for 12th day of the current month:
select DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 12)
Converting 'Sun' or 'Sat' to date is a bit more difficult. First, they aren't quite deterministic. If today is Friday, "Sunday this week" means "next Sunday" in some parts of the world and "last Sunday" in others. You should implement your own logic based on the value returned by DATEPART(dw, GETDATE()) (which will give you the day of the week).
To find the weekday of the current month
DECLARE #daynumber INT = 12
SELECT datename(weekday, dateadd(d, #daynumber - 1, getdate()))
To find the dates of the current month of a given weekday
DECLARE #dayname char(3) = 'sat'
;WITH CTE as
(
SELECt TOP
(datediff(D, eomonth(getdate(), -1),eomonth(getdate())))
dateadd(d,row_number()over(ORDER BY 1/0),
eomonth(getdate(),-1))date
FROM
(values(1),(2),(3),(4),(5),(6))x(x),
(values(1),(2),(3),(4),(5),(6))y(x)
)
SELECT day(date) monthday, date
FROM CTE
WHERE left(datename(weekday, date),3) = #dayname
select sysdatetime(); --2018-12-13 16:29:56.0560574
---If I give 12 for instance I want to get the date of 12th day of this month.
declare #numDate int = 12;
select dateadd(m, datediff(m,0,getdate()),#numDate - 1 ); --2018-12-12 00:00:00.000
--Or if I give 'Sun' or 'Sat' is it possible to get the dates of these days ?
declare #text nvarchar(20) = 'Sunday';
declare #dateStart date = dateadd(month, datediff(month, 0, sysdatetime()), 0),
#days int =( select (DAY(dateadd(dd,-1,DATEADD(m,1,cast(2018 as varchar(4)) + '-' + cast(12 as varchar(2)) +'-01')))));
declare #dateEnd date = DATEADD(day,#days-1,#dateStart);
;WITH CTE (Dates,EndDate) AS
(
SELECT #dateStart AS Dates,#dateEnd AS EndDate
UNION ALL
SELECT DATEADD(day,1,Dates),EndDate
FROM CTE
WHERE DATEADD(day,1,Dates) <= EndDate
)
SELECT CTE.Dates, DATENAME(DW, CTE.Dates)
FROM CTE
where DATENAME(DW, CTE.Dates) = #text;
Result:
Dates,Day
2018/12/2,Sunday
2018/12/9,Sunday
2018/12/16,Sunday
2018/12/23,Sunday
2018/12/30,Sunday
-- Here is how to get week day name to week day number
DECLARE #T TABLE (Dow INT, NameOfDay VARCHAR(15), ShortName CHAR(3));
WITH Days AS
(
SELECT TOP 7
ROW_NUMBER() OVER(PARTITION BY object_id ORDER BY object_id) AS RowNo
FROM
sys.all_columns
)
INSERT INTO #T
SELECT
RowNo,
DATENAME(WEEKDAY, RowNo - 1),
LEFT(DATENAME(WEEKDAY, RowNo - 1), 3)
FROM
Days
SELECT
*
FROM
#T;
-- Here is how to get start of period
SELECT
DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0) AS StartOfDay,
DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0) AS StartOfWeek,
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) AS StartOfMonth,
DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0) AS StartOfYear;
-- An example
WITH
StartPeriods AS
(
SELECT DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0) AS StartOfWeek
),
SelectedDay AS
(
SELECT
Dow - 1 AS Dow,
(SELECT StartOfWeek FROM StartPeriods) AS StartOfWeek
FROM
#T
WHERE
ShortName = 'Wed'
)
SELECT
DATEADD(DAY, Dow, StartOfWeek)
FROM
SelectedDay;
I am looking for a SQL server function which can count the number of hours between 2 given datetime values, but excludes the hours between 6pm on Friday and 6am on Monday.
I'd like to be able to use this as a custom datediff, but also as a custom dateadd (eg adding 4 hours to 5pm a Friday, will return following Monday 9am)
I currently have something which excludes Sat/Sun based on the weekday number but this doesn't take the Fri/Mon hours into account.
This uses a number table. Adjust weekend start/end in parmeters:
declare #d1 as datetime = '2018-06-01 05:30:00'
, #d2 as datetime = '2018-06-18 19:45:00'
, #FridayWE as int = 18 --6pm
, #MondayWS as int = 6 --6am
;WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n))
select count(*) as HoursBetweenDatetimes
from (
SELECT dateadd(hour, ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n, dateadd(hour, datediff(hour, 0, #d1), 0)) as [DateHour]
FROM x ones, x tens, x hundreds, x thousands
) a
where not ((DATEPART(dw,[DateHour]) = 6 and DATEPART(hour,[DateHour]) >= #FridayWE)
or (DATEPART(dw,[DateHour]) = 7 )
or (DATEPART(dw,[DateHour]) = 1 )
or (DATEPART(dw,[DateHour]) = 2 and DATEPART(hour,[DateHour]) < #MondayWS))
and [DateHour] < #d2
This is another option you can use, with a calendar table.
This is the generation of the calendar table. For this case it has just days from monday to friday and from 9am to 6pm, one day per row (this can be additional columns for your regular calendar table).
IF OBJECT_ID('tempdb..#WorkingCalendar') IS NOT NULL
DROP TABLE #WorkingCalendar
CREATE TABLE #WorkingCalendar (
StartDateTime DATETIME,
EndDateTime DATETIME)
SET DATEFIRST 1 -- 1: Monday, 7: Sunday
DECLARE #StartDate DATE = '2018-01-01'
DECLARE #EndDate DATE = '2025-01-01'
;WITH RecursiveDates AS
(
SELECT
GeneratedDate = #StartDate
UNION ALL
SELECT
GeneratedDate = DATEADD(DAY, 1, R.GeneratedDate)
FROM
RecursiveDates AS R
WHERE
R.GeneratedDate < #EndDate
)
INSERT INTO #WorkingCalendar (
StartDateTime,
EndDateTime)
SELECT
StartDateTime = CONVERT(DATETIME, R.GeneratedDate) + CONVERT(DATETIME, '09:00:00'),
EndDateTime = CONVERT(DATETIME, R.GeneratedDate) + CONVERT(DATETIME, '18:00:00')
FROM
RecursiveDates AS R
WHERE
DATEPART(WEEKDAY, R.GeneratedDate) BETWEEN 1 AND 5 -- From Monday to Friday
OPTION
(MAXRECURSION 0)
This is the query to calculate time differences between 2 datetimes. You can change the HOUR for anything you want, in all 3 places (MINUTE, SECOND, etc.) and the result will be displayed in that unit.
DECLARE #FromDate DATETIME = '2018-06-15 18:00:00'
DECLARE #ToDate DATETIME = '2018-06-18 10:00:00'
;WITH TimeDifferences AS
(
-- Date completely covered
SELECT
Difference = DATEDIFF(
HOUR,
W.StartDateTime,
W.EndDateTime)
FROM
#WorkingCalendar AS W
WHERE
W.StartDateTime >= #FromDate AND
W.EndDateTime <= #ToDate
UNION ALL
-- Filter start date partially covered
SELECT
Difference = DATEDIFF(
HOUR,
#FromDate,
CASE WHEN W.EndDateTime > #ToDate THEN #ToDate ELSE W.EndDateTime END)
FROM
#WorkingCalendar AS W
WHERE
#FromDate BETWEEN W.StartDateTime AND W.EndDateTime
UNION ALL
-- Filter end date partially covered
SELECT
Difference = DATEDIFF(
HOUR,
CASE WHEN W.StartDateTime > #FromDate THEN W.StartDateTime ELSE #FromDate END,
#ToDate)
FROM
#WorkingCalendar AS W
WHERE
#ToDate BETWEEN W.StartDateTime AND W.EndDateTime
)
SELECT
Total = SUM(T.Difference)
FROM
TimeDifferences AS T
This approach will consider each day from the calendar table, so if a particular day you have reduced hours (or maybe none from a Holiday) then the result will consider it.
You can use this query to add hours. Basically split each calendar range by hour, then use a row number to determine the amount of hours to add. Is this case you can't simply change the HOUR for MINUTE, it will require a few tweaks here and there if you need it.
DECLARE #FromDate DATETIME = '2018-06-14 12:23:12.661'
DECLARE #HoursToAdd INT = 15
;WITH RecursiveHourSplit AS
(
SELECT
StartDateTime = W.StartDateTime,
EndDateTime = W.EndDateTime,
HourSplitDateTime = W.StartDateTime
FROM
#WorkingCalendar AS W
UNION ALL
SELECT
StartDateTime = W.StartDateTime,
EndDateTime = W.EndDateTime,
HourSplitDateTime = DATEADD(HOUR, 1, W.HourSplitDateTime)
FROM
RecursiveHourSplit AS W
WHERE
DATEADD(HOUR, 1, W.HourSplitDateTime) < W.EndDateTime
),
HourRowNumber AS
(
SELECT
R.HourSplitDateTime,
RowNumber = ROW_NUMBER() OVER (ORDER BY R.HourSplitDateTime ASC)
FROM
RecursiveHourSplit AS R
WHERE
#FromDate < R.HourSplitDateTime
)
SELECT
DATETIMEFROMPARTS(
YEAR(R.HourSplitDateTime),
MONTH(R.HourSplitDateTime),
DAY(R.HourSplitDateTime),
DATEPART(HOUR, R.HourSplitDateTime),
DATEPART(MINUTE, #FromDate),
DATEPART(SECOND, #FromDate),
DATEPART(MILLISECOND, #FromDate))
FROM
HourRowNumber AS R
WHERE
R.RowNumber = #HoursToAdd
You can use similar logic to substract amount of hours by creating the row number with the rows that have datetimes before the supplied datetime (instead of after).
I would like to display month and year for my parameter for the end users to select from the drop down list.
For example the startdate has to be June 2017 and enddate is only month and year from getdate()
This is the query that I wrote but it's not working for me
declare #start datetime = '6/1/2017'
declare #end datetime = getdate()
select
#start = dateadd(M, #start),
datename(M, #start) + ' ' + datename(Y, #start)
where
#start < #end
There are some errors in your code:
Syntax of dateadd, correct dateadd(MONTH,1, #start)
You are returning the error A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.
Try these code
DECLARE #start DATETIME = '2017-01-01'
DECLARE #end DATETIME = Getdate();
WITH ctealldates
AS (SELECT #start startdate
,#end enddate
FROM (VALUES (1))G(n)
UNION ALL
SELECT Dateadd(month, 1, startdate) startdate
,enddate
FROM ctealldates
WHERE startdate < enddate)
SELECT Datename(month, startdate) + ' '
+ Datename(year, startdate) MonthName, year(startdate) * 100 + month(startdate) OrderBy
FROM ctealldates
ORDER BY
year(startdate) * 100 + month(startdate)
OPTION (maxrecursion 0);
MonthName OrderBy
------------------------------------------------------------- -----------
January 2017 201701
February 2017 201702
March 2017 201703
April 2017 201704
May 2017 201705
June 2017 201706
July 2017 201707
August 2017 201708
September 2017 201709
one Solution that i think will be as below.
Create a stored procedure as below
declare #start DATE = '2011-05-01'
declare #end DATE = getdate()
;with months (date)
AS
(
SELECT #start
UNION ALL
SELECT DATEADD(month,1,date)
from months
where DATEADD(month,1,date)<=#end
)
select Datename(month,date) As Months, Datename(year, date) As Years, CONCAT(Datename(month,date), ' ', Datename(year, date)) As MonthandYear from months
create a parameter for your report RDL, and for available values option select get values from Query.
Select created dataset from above query, in value field select MonthandYear field and label as 'Start Date'.
When you run the report you should receive input parameter as Start Date with drop down values for date difference with start date and end date.
hope this helps.
I'm trying to get all months in which no transaction is placed for the same year (If different years is not possible)
This is my query to get transactions between 2 dates, but don't know how can I select only months for which transaction in database is missing
SELECT *
FROM Installment
WHERE OrderId = 1
AND InstallmentDate
BETWEEN cast('8/02/2014' as date)
AND cast('12/25/2014' as date)
InstallmentId OrderId CustomerKey InstallmentAmount InstallmentDate
18 1 INS-1 3000 2014-09-03
92 1 INS-1 3000 2014-10-13
137 1 INS-1 3000 2014-11-05
in this case record for the 12th month and 8th month is missing, how can I get this with SQL Server Query ?
Update
select yymm.yy, yymm.mm
from (select distinct year(InstallmentDate) as yy, month(InstallmentDate) as mm
from Installment
where InstallmentDate BETWEEN '2014-09-02' and '2015-01-15'
) yymm left join
Installment i
on i.OrderId = 1 and
year(i.InstallmentDate) = yymm.yy and
month(i.InstallmentDate) = yymm.mm
where i.OrderId is not null;
Gordon's query is returning all the years and months from table between 2 dates, just by changing i.OrderId is null to i.OrderId is not null here is the out of his query
yy mm
2014 9
2014 10
2014 11
Expected Output (if possible)
yy mm
2014 12
2015 1
Using the following recursive CTE:
DECLARE #start DATE = '2014-09-02'
DECLARE #end DATE = '2015-01-15'
;WITH IntervalDates (date)
AS
(
SELECT #start
UNION ALL
SELECT DATEADD(MONTH, 1, date)
FROM IntervalDates
WHERE DATEADD(MONTH, 1, date)<=#end
)
SELECT YEAR(date) AS Year, MONTH(date) AS Month
FROM IntervalDates
you can get a list of all Years/Months between the two dates of interest:
Year Month
==============
2014 9
2014 10
2014 11
2014 12
2015 1
Using EXCEPT on the above CTE:
;WITH IntervalDates (date)
AS
(
SELECT #start
UNION ALL
SELECT DATEADD(MONTH, 1, date)
FROM IntervalDates
WHERE DATEADD(MONTH, 1, date)<=#end
)
SELECT YEAR(date) AS Year, MONTH(date) AS Month
FROM IntervalDates
EXCEPT
SELECT DISTINCT YEAR(InstallmentDate) AS yy, MONTH(InstallmentDate) AS mm
FROM Installment
WHERE OrderId = 1 AND InstallmentDate BETWEEN #start AND #end
yields the required result set:
Year Month
=============
2014 12
2015 1
To do this in SQL, you need to start with a list of months. Assuming you have at least one record for each month in the table, you can then get the missing dates easily using a subquery. The rest of the query is just a left join and checking for non-matches:
select yymm.yy, yymm.mm
from (select distinct year(InstallmentDate) as yy, month(InstallmentDate) as mm
from Installment
where InstallmentDate BETWEEN '2014-09-02' and '2015-01-15'
) yymm left join
Installment i
on i.OrderId = 1 and
year(i.InstallmentDate) = yymm.yy and
month(i.InstallmentDate) = yymm.mm
where i.OrderId is null;
Simplest way I can think of is to have a date dimension table that contains (at least) date, and 1st of month then. For creating one take a look at something like https://dba.stackexchange.com/questions/74957/best-approach-for-populating-date-dimension-table , although that one doesn't have firstOfMonthDate in it as my example show but the idea is the same.
then your query becomes
SELECT DISTINCT
firstOfMonthDate
FROM
dateRef dr
LEFT OUTER JOIN
InstallmentDate i ON dr.date = i.InstallmentDate AND i.OrderId = 1
WHERE
i.InstallmentDate IS NULL
AND
dr.date BETWEEN #startDate and #endDate
change firstOfMonthDate for fiscal month etc. as required. This would work across any range of dates you have in your table so different years wouldn't be an issue.
Try the below script. I retrieve all dates between the specified dates and use a LEFT JOIN to get those which are not present in your table:
DECLARE #startDate AS DATETIME, #endDate AS DATETIME
DECLARE #dates AS TABLE (CurrentDate DATETIME)
SET #startDate = '2014-01-01'
SET #endDate = '2014-01-31';
with GetDates AS
(
SELECT #startDate AS TheDate
UNION ALL
SELECT DATEADD("DD", 1, TheDate) FROM GetDates
WHERE TheDate < #endDate
) INSERT INTO #dates SELECT TheDate FROM GetDates
OPTION (MAXRECURSION 0)
SELECT DISTINCT YEAR(d.CurrentDate), MONTH(d.CurrentDate) FROM #dates d
LEFT JOIN InstallmentDate i ON i.InstallmentDate BETWEEN #startDate AND #endDate AND OrderId = 1
WHERE i.InstallmentDate IS NULL
Hope this helps...
In a view have these two dates coming from a table:
2014-12-17 14:01:03.523 - 2014-12-20 09:59:28.783
I need to know the date diff in hours assuming that in a day i can count the hours just from 08 AM and 5 PM.
Of course saturdays and sundays must not be included.
I tried using this code inside the select but i only got the diff in days, excluding saturdays and sundays.
(DATEDIFF(HOUR, convert(datetime,t.EXT_DATAINS-2), convert(datetime,b.EXT_DATAINS-2)) + 1)
-(DATEDIFF(wk, convert(datetime,t.EXT_DATAINS-2), convert(datetime,b.EXT_DATAINS-2)) * 2)
-(CASE WHEN DATENAME(dw, convert(datetime,t.EXT_DATAINS-2)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, convert(datetime,b.EXT_DATAINS-2)) = 'Saturday' THEN 1 ELSE 0 END) differenza
Example:
2014-12-17 : 3hrs
2014-12-18 : 8hrs
2014-12-19 : 8hrs
2014-12-20 : 2hrs
Tot : 21hrs
Use a Recursive CTE to get all Hours with Dates.
METHOD 1 : Get all dates with hours between FromDate and ToDate
DECLARE #FROMDATE DATETIME='2014-12-17 14:01:03.523'
DECLARE #TODATE DATETIME='2014-12-20 09:59:28.783'
;WITH CTE AS
(
SELECT #FROMDATE FROMDATE
UNION ALL
SELECT DATEADD(HH,1,FROMDATE)
FROM CTE
WHERE FROMDATE<#TODATE
)
SELECT ISNULL(CAST(CAST(FROMDATE AS DATE)AS VARCHAR(12)),'Tot')FROMDATE,
CAST(COUNT(FROMDATE)AS VARCHAR(4))+'hrs' [HOURS]
FROM CTE
WHERE DATEPART(HH,FROMDATE) BETWEEN 9 AND 16
AND DATENAME(DW,FROMDATE)<>'SATURDAY' AND DATENAME(DW,FROMDATE)<>'SUNDAY'
GROUP BY CAST(FROMDATE AS DATE)
WITH ROLLUP
SQL FIDDLE
METHOD 2 : Gets missing dates between FromDate and ToDate with 8 as hardcoded as Hrs
This method will be more implementable - Performance Tuned
DECLARE #FROMDATE DATETIME='2014-12-17 14:01:03.523'
DECLARE #TODATE DATETIME='2014-12-20 09:59:28.783'
;WITH CTE AS
(
-- Get missing dates between FromDate and ToDate
SELECT DATEADD(DAY,1,#FROMDATE) FROMDATE,8 HRS
UNION ALL
SELECT DATEADD(DAY,1,FROMDATE),8
FROM CTE
WHERE FROMDATE < DATEADD(DAY,-1,#TODATE)
)
,CTE2 AS
(
-- Gets the Hours for FromDate
SELECT CAST(#FROMDATE AS DATE) DATES, CAST(CAST(DATEDIFF
(
MINUTE,#FROMDATE,CAST(CAST(CAST(#FROMDATE AS DATE) AS VARCHAR(12))+' 17:00:00' AS DATETIME)
)AS NUMERIC(18,2))/60 AS DECIMAL(18,0)) HRS
WHERE DATENAME(DW,#FROMDATE)<>'SATURDAY' AND DATENAME(DW,#FROMDATE)<>'SUNDAY'
UNION ALL
-- Select Hours in between dates
SELECT CAST(FROMDATE AS DATE) NEWDATE,HRS
FROM CTE
WHERE DATENAME(DW,FROMDATE)<>'SATURDAY' AND DATENAME(DW,FROMDATE)<>'SUNDAY'
UNION ALL
-- Select Hours for ToDate
SELECT CAST(#TODATE AS DATE), CAST(CAST(DATEDIFF
(
MINUTE,CAST(CAST(CAST(#TODATE AS DATE) AS VARCHAR(12))+' 08:00:00' AS DATETIME),#TODATE
)AS NUMERIC(18,2))/60 AS DECIMAL(18,0))
WHERE DATENAME(DW,#TODATE)<>'SATURDAY' AND DATENAME(DW,#TODATE)<>'SUNDAY'
)
-- Use ROLLUP to find the sum of Hours and show it in last row
SELECT ISNULL(CAST(DATES AS VARCHAR(20)),'Tot')DATES,
CAST(SUM(HRS)AS VARCHAR(4))+'hrs' HRS
FROM CTE2
GROUP BY DATES
WITH ROLLUP
SQL FIDDLE
#marco burrometo
Create a static table which will have all the calendar functionality like holiday functionality,saturday and sunday is a holiday. It will help you a lot.