Related
I have a report which looks for orders during a given date range... It returns the DateName from the report to give me mondays, it then gives me times from the report, to give me 859 for 08:59 for example.. I then use a case on this report to do the following...
WHEN (DATENAME(DW,T1.DocDate)) = 'Monday' AND T1.DocTime >= '700' AND T1.DocTime <= '859' THEN '1 Monday 07:00-08:59'
What I want to achieve, is the count for "1 Monday 07:00-08:59" to be divided by 2 if there has been 2 mondays, divided by 3 if there has been 3 mondays etc... but I have to be able to have it divide by 3 mondays for example, but 2 wednesdays if the date is a tuesday...
The report currently gives a Total of all orders placed in a datetime grouped together but has no division to average for each day.
SELECT (DATENAME(DW, T1.DocDate)) AS Weekday,
T1.DocTime AS Time,
SUM(T1.DocTotal) AS Value,
CASE
WHEN (DATENAME(DW, T1.DocDate)) = 'Monday'
AND T1.DocTime >= '700'
AND T1.DocTime <= '859' THEN '1 Monday 07:00-08:59'
FROM ORDR T1
INNER JOIN OCRD T0 ON T0.CardCode = T1.CardCode
WHERE (T1.DocDate >= #Start
AND T1.DocDate <= #End)
AND T0.QryGroup20 = 'Y'
AND T1.Canceled = 'N'
GROUP BY T1.DocTime,
T1.DocDate;
I expect the report to count the mondays / tuesdays etc that occur between #START and #END to give me an average sale per day and time.Then be able to then somehow divide by the count of the defined days in the case statement. (I'll hopefully be doing this part in Crystal Reports) but if i can get the first part, I'll work on the second half.
Just cross join the DW_Count subquery, which returns the count of every weekday in your orders range. Then you can count your avg for each weekday
SELECT (DATENAME(DW, T1.DocDate)) AS Weekday,
T1.DocTime AS Time,
SUM(T1.DocTotal) AS Value,
SUM(T1.DocTotal)/(CASE WHEN DATENAME(DW, T1.DocDate) = 'Monday' then DW_Count.MonCount
WHEN DATENAME(DW, T1.DocDate) = 'Tuesday' then DW_Count.TueCount
WHEN DATENAME(DW, T1.DocDate) = 'Wednesday' then DW_Count.WedCount
WHEN DATENAME(DW, T1.DocDate) = 'Thursday' then DW_Count.ThuCount
WHEN DATENAME(DW, T1.DocDate) = 'Friday' then DW_Count.FriCount
WHEN DATENAME(DW, T1.DocDate) = 'Saturday' then DW_Count.SatCount
WHEN DATENAME(DW, T1.DocDate) = 'Sunday' then DW_Count.SunCount) AS AvgValue
CASE
WHEN (DATENAME(DW, T1.DocDate)) = 'Monday'
AND T1.DocTime >= '700'
AND T1.DocTime <= '859' THEN '1 Monday 07:00-08:59'
FROM ORDR T1
INNER JOIN OCRD T0 ON T0.CardCode = T1.CardCode
CROSS JOIN (select sum(case when DATENAME(DW, DW_Count.DateValue) = 'Monday' then 1 else 0 end) as MonCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Tuesday' then 1 else 0 end) as TueCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Wednesday' then 1 else 0 end) as WedCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Thursday' then 1 else 0 end) as ThuCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Friday' then 1 else 0 end) as FriCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Saturday' then 1 else 0 end) as SatCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Sunday' then 1 else 0 end) as SunCount
from (select distinct DocDate from ORDR where (T1.DocDate >= #Start AND T1.DocDate <= #End))) AS DW_Count
WHERE (T1.DocDate >= #Start
AND T1.DocDate <= #End)
AND T0.QryGroup20 = 'Y'
AND T1.Canceled = 'N'
GROUP BY T1.DocTime,
T1.DocDate;
You can use the below logic-
For MSSQL
DECLARE #DT1 DATE = '20190802'
DECLARE #DT2 DATE = '20190820'
DECLARE #SatCount INT = 0
WHILE #DT1<= #DT2
BEGIN
SET #SatCount = #SatCount + CASE WHEN DATEPART(WeekDay,#DT1) = 7 THEN 1 ELSE 0 END
SET #DT1 = DATEADD(DD,1,#DT1)
END
SELECT #SatCount
Just one more option-
DECLARE #DT1 DATE = '20190802',
#DT2 DATE = '20190920';
SELECT SUM(CASE WHEN DATEPART(WeekDay,Date) = 7 THEN 1 ELSE 0 END)
FROM
(
SELECT TOP (DATEDIFF(DAY, #DT1, #DT2) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #DT1)
FROM sys.all_objects a
-- A System table just used for creating multiple rows.
CROSS JOIN sys.all_objects b
-- CROSS JOIN will create number of row = original number of row X original number of row.
)A
I have this table where I am specifying Holidays in week. I want to calculate total working days between 2 specific dates using these fields.
CREATE TABLE [tbl_Shift](
[OffDay1] [nvarchar](25) NOT NULL CONSTRAINT [DF_tbl_Shift_OffDay1] DEFAULT (N'Sunday'),
[IsAlternateOffDay2] [bit] NULL,
[OffDay2] [nvarchar](25) NULL
)
INSERT INTO [tbl_Shift] VALUES ('Sunday', 'True', 'Saturday')
I have this query written but I am not able to get correct days. It should give 23 days as there are 2 holidays in each week and 31 days in total but I'm getting 26 days.
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2018/05/01'
SET #EndDate = '2018/05/31'
SELECT
(DATEDIFF(dd, #StartDate, #EndDate+1)) -(DATEDIFF(wk, #StartDate, #EndDate))
-(CASE WHEN IsAlternateOffday2 = 1 THEN 1 END) FROM HRM.tbl_Shift
this will give 23:
SELECT
(DATEDIFF(dd, #StartDate, #EndDate+1)) -(DATEDIFF(wk, #StartDate, #EndDate))
-ISNULL((CASE WHEN IsAlternateOffday2 = 1 THEN (DATEDIFF(wk, #StartDate, #EndDate)) END), 0)
FROM HRM.tbl_Shift
This subtracts 2 days for every weekend. Check your server config if Sunday is first or last day of the week. This can throw things off by a weekend.
SELECT DATEPART(WEEKDAY,'20180506') --Checks if Sunday is Day 1 or Day 7
DECLARE #start DATETIME = '20180501'
DECLARE #end DATETIME = '20180531'
SELECT DATEDIFF(DAY,#start,#end+1) - (DATEDIFF(WEEK,#start,#end+1)*2)
UPDATE:
Use COALESCE to replace NULLS with an alternative value.
DECLARE #offdate DATETIME = NULL
SELECT COALESCE(#offdate,GETDATE())
Try This
DECLARE #StartDate DATE ='2018-05-01',
#EndDate DATE ='2018-05-31'
;WITH CTE
AS
(
SELECT DATEADD(DD,Number-1,#StartDate) MOnthDates,
DATENAME(DW,DATEADD(DD,Number-1,#StartDate)) As DayNAmes,
CASE WHEN DATENAME(DW,DATEADD(DD,Number-1,#StartDate)) IN ('Saturday','Sunday') THEN 0 ELSE 1 END WeekDays
FROM master.dbo.spt_values
WHERE [Type]='P'
AND Number Between 1 AND 10000
)
SELECT COUNT(WeekDays) AS WeekDaysCount
FROM CTE
WHERE WeekDays<>0
AND MOnthDates Between #StartDate AND DATEADD(DAY,1,#EndDate)
Result
WeekDaysCount
-------------
23
Demo:http://rextester.com/TOLYT35075
This was what I created after reviewing the answers. I needed the number of days per month for several months. The below will provide that, and insert it into the #MonthDayCount table. Note: I named a field Month, even though that is a SQL Server defined term; you can change it if needed.
You must enter the first day of the month and the last for it to count the first and last month correctly. If you entered 1/2/2022, it would result in January being short one day.
DECLARE #StartDate DATE = '1/01/2021'--The start of the first month the number of days are needed for.
DECLARE #EndDate DATE = '1/31/2021'--The end of the first month the number of days are needed for.
DECLARE #FinalDate DATE = '12/31/2022'--This is the last month that will be inserted. Includes this month.
IF OBJECT_ID('tempdb..#MonthDayCount', 'U') IS NOT NULL
DROP TABLE #MonthDayCount;
CREATE TABLE #MonthDayCount
(
[Month] VARCHAR(MAX),
[# of WeekDays] INT,
[EOM] DATE
)
WHILE #StartDate <= #FinalDate
BEGIN
INSERT INTO
#MonthDayCount
VALUES (
DATENAME(m,#StartDate),
(
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
),
#EndDate
)
SET #StartDate = DATEADD(m,1,#StartDate)
SET #EndDate = EOMONTH(#EndDate,1)
END
MS SQL Server query to find count of all the working days (non Saturdays and Sundays) in current month.
Works in SQL Server, Azure Synapse Analytics
Note:
Change the getdate() as per your need.
SELECT Day(Eomonth(Getdate())) - ( Datediff(d, Dateadd(d, Datediff(d, -1,
Dateadd(month, Month(
Getdate()) - 1 + (
Year(Getdate()
) - 1900 )
*
12, 6)) / 7 * 7, -1),
Dateadd(m, 1, Dateadd(
month,
Month(Getdate())
- 1 +
(
Year(Getdate()) - 1900 )
*
12, 6
)
)) / 7 +
Datediff(d, Dateadd(d, Datediff(d, -1,
Dateadd(
month,
Month(Getdate()) - 1 + (
Year(Getdate()
) - 1900 )
*
12, 7)) / 7 * 7, -1), Dateadd(m, 1,
Dateadd(month, Month(Getdate()) - 1 +
(
Year(Getdate()) - 1900 ) *
12, 7)
)) / 7 ) AS Num_Working_Days
Can I find the date of a day that is on which dates the Saturdays and Sundays of a specific month fall? For e.g consider the month of JANUARY-2017. The following dates are weekend days:
7/1/2017 - Saturday
14/1/2017 - Saturday
21/1/2017 - Saturday
28/1/2017 - Saturday
1/1/2017 - Sunday
8/1/2017 - Sunday
15/1/2017 - Sunday
22/1/2017 - Sunday
29/1/2017 - Sunday
I want a SQL Server query for this such that when I pass in month and year as input, I should get back all the above dates (only dates of Saturday and Sunday) as output
I do not wish to use any user defined function and want to finish it in a single SELECT statement
Note: As already noted by another user in the comments, this query depends upon your server settings, namely DATEFIRST. If you need alterations to the query because of different settings, just tell me and I can change it around for you.
Using a CTE as dummy data...
/* Ignore this part...*/
WITH CTE AS
(
SELECT CAST('01/01/2017' AS DATE) AS [Date]
UNION ALL
SELECT DATEADD(DAY,1,[Date])
FROM CTE
WHERE DATE <= '12/31/2017'
)
/*Your actual SELECT statement would look like this, from your own table of course*/
SELECT
[Date]
,CASE DATEPART(dw,[Date])
WHEN 1 THEN 'Sunday'
WHEN 2 THEN 'Monday'
WHEN 3 THEN 'Tuesday'
WHEN 4 THEN 'Wednesday'
WHEN 5 THEN 'Thursday'
WHEN 6 THEN 'Friday'
WHEN 7 THEN 'Saturday'
END
FROM CTE
WHERE DATEPART(dw,[Date]) IN (1,7)
AND MONTH([Date]) = 12--<month>
AND YEAR([Date]) = 2017--<year>
OPTION (MAXRECURSION 0) -- You won't need this line if you're querying a real table
;
If running that works for you, then your real query would probably look something like this:
SELECT
[Date]
,CASE DATEPART(dw,[Date])
WHEN 1 THEN 'Sunday'
WHEN 2 THEN 'Monday'
WHEN 3 THEN 'Tuesday'
WHEN 4 THEN 'Wednesday'
WHEN 5 THEN 'Thursday'
WHEN 6 THEN 'Friday'
WHEN 7 THEN 'Saturday'
END
FROM < the table you want >
WHERE DATEPART(dw,[Date]) IN (1,7) -- Only Sundays and Saturdays
AND MONTH([Date]) = < the month you want >
AND YEAR([Date]) = < the year you want >
;
If you want to generate the data, then a CTE is the way to go. If you're passing parameters, it would look something like this:
DECLARE
#MONTH INT
,#YEAR INT
;
SET #MONTH = 1;
SET #YEAR = 2017;
WITH CTE AS
(
SELECT CAST(CAST(#MONTH AS VARCHAR(2)) + '/01/' + CAST(#YEAR AS VARCHAR(4)) AS [Date]) AS DATE
UNION ALL
SELECT DATEADD(DAY,1,[Date])
FROM CTE
WHERE DATE <= CAST(#MONTH AS VARCHAR(2)) +
CASE
WHEN #MONTH IN (9,4,6,11)
THEN '/30/'
WHEN #MONTH IN (1,3,5,7,8,10,12)
THEN '/31/'
WHEN #MONTH = 2 AND #YEAR/4.00 = #YEAR/4
THEN '/29/'
ELSE '/28/'
END
+ CAST(#YEAR AS VARCHAR(4))
)
SELECT
[Date]
,CASE DATEPART(dw,[Date])
WHEN 1 THEN 'Sunday'
WHEN 2 THEN 'Monday'
WHEN 3 THEN 'Tuesday'
WHEN 4 THEN 'Wednesday'
WHEN 5 THEN 'Thursday'
WHEN 6 THEN 'Friday'
WHEN 7 THEN 'Saturday'
END
FROM CTE
WHERE DATEPART(dw,[Date]) IN (1,7)
OPTION (MAXRECURSION 0)
;
Please try this one.
DECLARE #Year AS INT=2017,
#Month AS INT=3,
#FirstDateOfYear DATETIME,
#LastDateOfYear DATETIME
SELECT #FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
SELECT #LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0)
-- Creating Query to Prepare Year Data
;WITH cte AS (
SELECT 1 AS DayID,
#FirstDateOfYear AS FromDate,
DATENAME(dw, #FirstDateOfYear) AS Dayname
UNION ALL
SELECT cte.DayID + 1 AS DayID,
DATEADD(d, 1 ,cte.FromDate),
DATENAME(dw, DATEADD(d, 1 ,cte.FromDate)) AS Dayname
FROM cte
WHERE DATEADD(d,1,cte.FromDate) < #LastDateOfYear
)
SELECT FromDate AS Date, Dayname
FROM CTE
WHERE DayName IN ('Saturday','Sunday') and month(FromDate) = #Month
OPTION (MaxRecursion 370)
This should do the trick:
DECLARE #month date = '2017-01-01'
SET #month = dateadd(month, datediff(month, 0, #month), 0)
;WITH CTE as
(
SELECT 0 x
FROM (values(1),(1),(1),(1),(1),(1)) x(n)
),
CTE2 as
(
SELECT
top(day(eomonth(#month)))
-- use this syntax for sqlserver 2008
-- top(datediff(d, #month,dateadd(month,1,#month)))
cast(dateadd(d, row_number()over(order by(select 1))-1,#month) as date) cDate
FROM CTE CROSS JOIN CTE C2
)
SELECT
cDate,
datename(weekday, cDate) Weekday
FROM CTE2
WHERE
datediff(d,0,cDate)%7 > 4
Fiddle
From https://www.sqlservercentral.com/articles/finding-the-correct-weekday-regardless-of-datefirst, you simply:
(DATEPART(dw, #your_date) + ##DATEFIRST) % 7 NOT BETWEEN 2 AND 6
As requested, single select, language neutral, dateFirst neutral, almost SQL version neutral:
declare #OneDate datetime = '28/01/2017'; -- Any date from the target month/year
select MyDate -- raw date or ...
-- convert(varchar, MyDate, 103) + ' - ' + dateName(dw, MyDate) -- as Sample
as WeekEndDate
from (
select dateAdd(dd, number, dateAdd(mm, dateDiff(mm, 0, #OneDate), 0)) as MyDate
from master..spt_values
where type = 'P' and number < 31
) j
where 1 + (datePart(dw, MyDate) + ##DATEFIRST + 5) % 7 in (6, 7)
and month(MyDate) = month(#OneDate)
-- order by 1 + (datePart(dw, MyDate) + ##DATEFIRST + 5) % 7, MyDate -- as Sample
;
Another way to solve this problem as follow -
DECLARE #MONTH INT,#YEAR INT
SET #MONTH = 1;
SET #YEAR = 2017;
Declare #StartDate date =CAST(CAST(#MONTH AS VARCHAR(2)) + '/01/' + CAST(#YEAR AS VARCHAR(4)) AS [Date]), #EndDate date
Set #EndDate = EOMONTH(#StartDate)
Declare #Temp table (DateOfDay date, DaysName varchar(50))
While(#StartDate <= #EndDate)
Begin
Insert into #Temp
SELECT #StartDate DateOfMonth,
case when DATENAME(DW, #StartDate) = 'Saturday' then DATENAME(DW, #StartDate)
when DATENAME(DW, #StartDate) = 'Sunday' then DATENAME(DW, #StartDate)
end DaysName
set #StartDate = DATEADD(d,1,#StartDate)
End
select * from #Temp where DaysName is not null order by DaysName, DateOfDay
Can't you do something like this?
SELECT DATENAME(dw,'10/11/2016') AS DATE
WHERE DATE CONTAINS('Saturday') OR DATE CONTAINS('SUNDAY')
and instead of '10/11/2016' you only have to figure out how to generate all the dates in a month/year?
I have 2 Sets for Date Ranges :
#StartDate and #EndDate : Being passed to a stored procedure
ProjectStartDate and ProjectEndDate : In the Database
The goal is to get the number of working days (public holidays are ignored) that ProjectStartDate and ProjectEndDate fall between #StartDate and #EndDate.
Example 1:
#StartDate = 2016/03/21
#EndDate = 2016/03/25
ProjectStartDate = 2016/03/13
ProjectEndDate = 2016/03/22
So the number of working days I need to work out are where ProjectStartDate and ProjectEndDate fall beween #StartDate and #Endate - in this case, number of working days would be 2(Mon - Fri)
Example 2 :
ProjectStartDate = 2016/03/22
ProjectEndDate = 2016/03/29
So the number of working days I need to work out are where ProjectStartDate and ProjectEndDate fall between #StartDate and #Endate - in this case, number of working days would be 4(Mon - Fri)
Example 3 :
ProjectStartDate = 2016/03/13
ProjectEndDate = 2016/03/29
So the number of working days I need to work out are where ProjectStartDate and ProjectEndDate fall between #StartDate and #Endate - in this case, number of working days would be 5(Mon - Fri)
The code I have to work out the working days is as follows :
(DATEDIFF(dd, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) + 1)
-(DATEDIFF(wk, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) * 2)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Saturday' THEN 1 ELSE 0 END)
I have tried to get the result, but it partially works. I know there is a simpler way of doing this :
CASE WHEN(CASE WHEN #StartDate <= ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)
THEN (DATEDIFF(dd, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), #EndDate) + 1)
-(DATEDIFF(wk, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), #EndDate) * 2)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Saturday' THEN 1 ELSE 0 END)
ELSE (DATEDIFF(dd, #StartDate, ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) + 1)
-(DATEDIFF(wk, #StartDate, ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) * 2)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Saturday' THEN 1 ELSE 0 END) END) >= 5
THEN 5
ELSE (CASE WHEN #StartDate <= ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)
THEN (DATEDIFF(dd, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), #EndDate) + 1)
-(DATEDIFF(wk, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), #EndDate) * 2)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Saturday' THEN 1 ELSE 0 END)
ELSE (DATEDIFF(dd, #StartDate, ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) + 1)
-(DATEDIFF(wk, #StartDate, ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) * 2)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Saturday' THEN 1 ELSE 0 END) END) END AS DaysCalculated
So I ended up finding the answer, it seems. I would prefer to find a cleaner, neater way... but I cant spend more time on this and this works for now. If Anyone has a cleaner, neater option, please let me know. Thanks.
(CASE WHEN ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart) >= #StartDate AND
ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd) >= #EndDate
THEN
(DATEDIFF(dd, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), #EndDate) + 1)
-(DATEDIFF(wk, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), #EndDate) * 2)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Saturday' THEN 1 ELSE 0 END)
ELSE
(CASE WHEN ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart) >= #StartDate AND
ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd) <= #EndDate
THEN
(DATEDIFF(dd, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) + 1)
-(DATEDIFF(wk, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart), ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) * 2)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart)) = 'Saturday' THEN 1 ELSE 0 END)
ELSE
(CASE WHEN ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart) <= #StartDate AND
ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd) <= #EndDate
THEN
(DATEDIFF(dd, #StartDate, ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) + 1)
-(DATEDIFF(wk, #StartDate, ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd)) * 2)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Saturday' THEN 1 ELSE 0 END)
ELSE
(CASE WHEN ISNULL(AA.DDAreaActivityActualStart,AA.DDAreaActivityPlannedStart) <= #StartDate AND
ISNULL(AA.DDAreaActivityActualEnd,AA.DDAreaActivityPlannedEnd) >= #EndDate
THEN
(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, #StartDate) = 'Saturday' THEN 1 ELSE 0 END)
END) END) END) END) AS CalculatedDays
How about this
declare #StartDate date = '2016-03-21',
#EndDate date = '2016-03-25'
; with tbl (ProjectStartDate , ProjectEndDate) as
(
select '2016-03-13', '2016-03-22' union all
select '2016-03-22', '2016-03-29' union all
select '2016-03-13', '2016-03-29'
)
select *,
[working days] = datediff( day,
case when ProjectStartDate > #StartDate then ProjectStartDate else #StartDate end,
case when ProjectEndDate < #EndDate then ProjectEndDate else #EndDate end
) + 1
from tbl
If I have 2 dates, I know I can work out how many days, hours, minutes etc are between the 2 dates using datediff, e.g:
declare #start datetime;
set #start = '2013-06-14';
declare #end datetime;
set #end = '2013-06-15';
select datediff( hour, #start, #end );
How do I figure out if the date range includes a weekend?
The reason why I want to know if the date range includes a weekend is because I want to subtract the weekend from the day or hour count. i.e. if the start day is Friday, and the end date is Monday, I should only get 1 days or 24 hours.
Datepart 1 = Sunday, and datepart 7 = Saturday on my server.
I have a function that calculates working days between 2 dates, the basic query is
declare #start datetime;
set #start = '2013-06-14';
declare #end datetime;
set #end = '2013-06-17';
SELECT
(DATEDIFF(dd, #Start, #end) +1) -- total number of days (inclusive)
-(DATEDIFF(wk, #Start, #end) * 2) -- number of complete weekends in period
-- remove partial weekend days, ie if starts on sunday or ends on saturday
-(CASE WHEN DATENAME(dw, #Start) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #end) = 'Saturday' THEN 1 ELSE 0 END)
so you could work out if dates include weekend if working days different to datediff in days
SELECT case when (DATEDIFF(dd, #Start, #end) +1) <>
(DATEDIFF(dd, #Start, #end) +1) -- total number of days (inclusive)
-(DATEDIFF(wk, #Start, #end) * 2) -- number of complete weekends in period
-- remove partial weekend days, ie if starts on sunday or ends on saturday
-(CASE WHEN DATENAME(dw, #Start) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #end) = 'Saturday' THEN 1 ELSE 0 END) then 'Yes' else 'No' end as IncludesWeekends
or simpler
SELECT (DATEDIFF(wk, #Start, #end) * 2) +(CASE WHEN DATENAME(dw, #Start) = 'Sunday' THEN 1 ELSE 0 END) +(CASE WHEN DATENAME(dw, #end) = 'Saturday' THEN 1 ELSE 0 END) as weekendDays
You have a weekend day if any one of the following three conditions is true:
The day of week (as an integer) of the end date is less than the day of week of the start date
Either day is itself a weekend day
The range includes at least six days
.
select
Coalesce(
--rule 1
case when datepart(dw,#end) - datepart(dw,#start) < 0 then 'Weekend' else null end,
-- rule 2
-- depends on server rules for when the week starts
-- I think this code uses sql server defaults
case when datepart(dw,#end) in (1,7) or datepart(dw,#start) in (1,7) then 'Weekend' else null end,
--rule 3
-- six days is long enough
case when datediff(d, #start, #end) >= 6 then 'Weekend' Else null end,
-- default
'Weekday')
One way, just showing you how you can use a table of numbers for this
declare #start datetime;
set #start = '2013-06-14';
declare #end datetime;
set #end = '2013-06-15'; -- play around by making this 2013-06-14 and other dates
IF EXISTS (SELECT * FROM(
SELECT DATEADD(dd,number,#start) AS SomeDAte
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(dd,number,#start) BETWEEN #start AND #end) x
WHERE DATEPART(dw,SomeDate) IN(1,7)) -- US assumed here
SELECT 'Yes'
ELSE
SELECT 'No'
Example to return all weekends between two dates
declare #start datetime;
set #start = '2013-06-14';
declare #end datetime;
set #end = '2013-06-30';
SELECT DATEADD(dd,number,#start) AS SomeDAte
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(dd,number,#start) BETWEEN #start AND #end
AND DATEPART(dw,DATEADD(dd,number,#start)) IN(1,7)
Results
2013-06-15 00:00:00.000
2013-06-16 00:00:00.000
2013-06-22 00:00:00.000
2013-06-23 00:00:00.000
2013-06-29 00:00:00.000
2013-06-30 00:00:00.000
You can use following functions. The first moves a given start- or enddate to monday(friday if backwards) if it begins in the weekend. The second calculates the seconds between two dates without weekends. Then you just need to check if the total-days equals the days without weksends(demo below).
CREATE FUNCTION [dbo].[__CorrectDate](
#date DATETIME,
#forward INT
)
RETURNS DATETIME AS BEGIN
IF (DATEPART(dw, #date) > 5) BEGIN
IF (#forward = 1) BEGIN
SET #date = #date + (8 - DATEPART(dw, #date))
SET #date = DateAdd(Hour, (8 - DatePart(Hour, #date)), #date)
END ELSE BEGIN
SET #date = #date - (DATEPART(dw, #date)- 5)
SET #date = DateAdd(Hour, (18 - DatePart(Hour, #date)), #date)
END
SET #date = DateAdd(Minute, -DatePart(Minute, #date), #date)
SET #date = DateAdd(Second, -DatePart(Second, #date), #date)
END
RETURN #date
END
GO
CREATE FUNCTION [dbo].[__DateDiff_NoWeekends](
#date1 DATETIME,
#date2 DATETIME
)
RETURNS INT AS BEGIN
DECLARE #retValue INT
SET #date1 = dbo.__CorrectDate(#date1, 1)
SET #date2 = dbo.__CorrectDate(#date2, 0)
IF (#date1 >= #date2)
SET #retValue = 0
ELSE BEGIN
DECLARE #days INT, #weekday INT
SET #days = DATEDIFF(d, #date1, #date2)
SET #weekday = DATEPART(dw, #date1) - 1
SET #retValue = DATEDIFF(s, #date1, #date2) - 2 * 24 * 3600 * ((#days + #weekday) / 7)
END
RETURN #retValue
END
Then you can get the info in this way:
declare #start datetime
set #start = '20130614'
declare #end datetime
set #end = '20130615'
declare #daysTotal int
declare #daysWoWeekends int
SET #daysTotal = DATEDIFF(dd, #start, #end)
SET #daysWoWeekends = dbo.__DateDiff_NoWeekends(#start, #end) / (24 * 3600)
SELECT CASE WHEN #daysTotal = #daysWoWeekends
THEN 'No weekend between'
ELSE 'There are weeksends' END,
#daysTotal,
#daysWoWeekends,#start,#end
Here's a demo: http://sqlfiddle.com/#!6/7cda7/11
There are weeksends 1 0 June, 14 2013 00:00:00+0000 June, 15 2013 00:00:00+0000
Here is the simple and generalize query . you can achieve result through recursive query . Check following query
with mycte as
(
select cast('2013-06-14' as datetime) DateValue
union all
select DateValue + 1 from mycte where DateValue + 1 < '2013-06-17'
)
select count(*) as days , count(*)*24 as hours
from mycte
WHERE DATENAME(weekday ,DateValue) != 'SATURDAY' AND
DATENAME(weekday ,DateValue) != 'SUNDAY'
OPTION (MAXRECURSION 0)
it will definitely work for you .
You can use a recursive CTE to get the dates between the range
WITH CTE_DatesTable
AS ( SELECT #MinDate AS [EffectiveDate]
UNION ALL
SELECT DATEADD(dd, 1, [EffectiveDate])
FROM CTE_DatesTable
WHERE DATEADD(dd, 1, [EffectiveDate]) <= #MaxDate )
SELECT [EffectiveDate]
FROM CTE_DatesTable
OPTION ( MAXRECURSION 0 );
and then Filter out the Weekends using ..
((DATEPART(dw, DT.EffectiveDate) + ##DATEFIRST) % 7) NOT IN (0, 1)
Similar problem, although in my case I wanted a onehot encoded binary list of columns (Mon-Sun) of whether two dates contain that DOW using Impala SQL.
select ...
max(case when tripduration > 6 then 1
when 2 >= dayofweek(tripstartdate) and 2 <= dayofweek(tripstartdate) + tripduration then 1
when 2 <= dayofweek(tripenddate) and 2 >= dayofweek(tripenddate) - tripduration then 1 else 0 end) as '2 mon',
max(case when tripduration > 6 then 1
when 3 >= dayofweek(tripstartdate) and 3 <= dayofweek(tripstartdate) + tripduration then 1
when 3 <= dayofweek(tripenddate) and 3 >= dayofweek(tripenddate) - tripduration then 1 else 0 end) as '3 tue',
max(case when tripduration > 6 then 1
when 4 >= dayofweek(tripstartdate) and 4 <= dayofweek(tripstartdate) + tripduration then 1
when 4 <= dayofweek(tripenddate) and 4 >= dayofweek(tripenddate) - tripduration then 1 else 0 end) as '4 wed',
max(case when tripduration > 6 then 1
when 5 >= dayofweek(tripstartdate) and 5 <= dayofweek(tripstartdate) + tripduration then 1
when 5 <= dayofweek(tripenddate) and 5 >= dayofweek(tripenddate) - tripduration then 1 else 0 end) as '5 thu',
max(case when tripduration > 6 then 1
when 6 >= dayofweek(tripstartdate) and 6 <= dayofweek(tripstartdate) + tripduration then 1
when 6 <= dayofweek(tripenddate) and 6 >= dayofweek(tripenddate) - tripduration then 1 else 0 end) as '6 fri',
max(case when tripduration > 6 then 1
when 7 >= dayofweek(tripstartdate) and 7 <= dayofweek(tripstartdate) + tripduration then 1
when 7 <= dayofweek(tripenddate) and 7 >= dayofweek(tripenddate) - tripduration then 1 else 0 end) as '7 sat',
max(case when tripduration > 6 then 1
when 1 >= dayofweek(tripstartdate) and 1 <= dayofweek(tripstartdate) + tripduration then 1
when 1 <= dayofweek(tripenddate) and 1 >= dayofweek(tripenddate) - tripduration then 1 else 0 end) as '1 sun'
from ....