SQL Only Include Working Hours in AVG Calculation - sql

I'v had a look through the forum but couldn't find anything specific enough for my scenario so here goes.
I have the following query which calculates the average time for a group of entries across multiple tables in a defined date period. The 3 types (IR, SR, CR) all are linked to a table (WorkItems). The Query I have for the average time is below. (the parameters are used in reporting services and a date picker)
Select
WIAvgAssign = AVG(
Case When WI.id Like 'IR%' Then DATEDIFF(hour,wi.CreatedDate,IR.FirstAssignedDate)
When WI.Id Like 'SR%' Then DATEDIFF(hour,wi.CreatedDate,SR.FirstAssignedDate)
When WI.Id Like 'SR%' Then DATEDIFF(hour,wi.CreatedDate,CR.FirstAssignedDate)
END),
IRAvgAssign = AVG(DATEDIFF(hour,wi.CreatedDate,IR.FirstAssignedDate)),
SRAvgAssign = AVG(DATEDIFF(hour,wi.CreatedDate,SR.FirstAssignedDate)),
CRAvgAssign = AVG(DATEDIFF(hour,wi.CreatedDate,CR.FirstAssignedDate))
from WorkItemDimvw WI
Left Outer Join IncidentDimvw IR on WI.EntityDimKey=IR.EntityDimKey
Left Outer Join ServiceRequestDimvw SR on WI.EntityDimKey=SR.EntityDimKey
Left Outer Join ChangeRequestDimvw CR on WI.EntityDimKey=CR.EntityDimKey
Where (IR.ResolvedDate >= #StartDate AND IR.ResolvedDate < #EndDate) OR
(SR.CompletedDate >= #StartDate AND SR.CompletedDate < #EndDate) OR
(CR.ActualEndDate >=#StartDate AND CR.ActualEndDate < #EndDate)
I have a table which contains each day of the week and the hours of operation for that particular day (the date is when the entry was created, it's just the time I'm interested in), the values for the weekend are blank.
Day Start Time End Time
Monday 2014-03-06 09:00:00.000 2014-03-06 17:00:00.000
Tuesday 2014-03-06 09:00:00.000 2014-03-06 17:00:00.000
Wednesday 2014-03-06 09:00:00.000 2014-03-06 17:00:00.000
Thursday 2014-03-06 09:00:00.000 2014-03-06 17:00:00.000
Friday 2014-03-06 09:00:00.000 2014-03-06 17:00:00.000
Saturday NULL NULL
Sunday NULL NULL
The average results in hours that I get currently are not specific to the hours of operation so I would like to be able to strip out when the office is closed and provide a more accurate average.
Thanks
Edit - I've come up with this, it's a bit inefficient as I've specified the number of non-working hours manually in the query and added in a calculation for weekends. Looking at the individual records I think it's correct. I've taken out the CR calculation for the time being
Declare #StartDate datetime
Declare #EndDate datetime
Set #StartDate = '2015/01/01'
Set #EndDate = '2015/12/31'
Select
AVG(
CASE WHEN CAST(wi.createddate as date) =
CAST(
CASE
WHEN WI.Id like 'IR%' then CASE WHEN ir.FirstAssignedDate !=NULL THEN ir.firstassigneddate else GETDATE() END
WHEN WI.Id like 'SR%' then CASE WHEN sr.firstassigneddate !=NULL THEN Sr.firstassigneddate else GETDATE() END
END
as date)
THEN DATEDIFF(HOUR,wi.CreatedDate,
CASE
WHEN WI.Id like 'IR%' then CASE WHEN ir.FirstAssignedDate !=NULL THEN ir.firstassigneddate else GETDATE() END
WHEN WI.Id like 'SR%' then CASE WHEN sr.firstassigneddate !=NULL THEN Sr.firstassigneddate else GETDATE() END
END)
ELSE (DATEDIFF(hour,wi.CreatedDate,DATEADD(hour,-15*DATEDIFF(day,wi.CreatedDate,CASE
WHEN WI.Id like 'IR%' then CASE WHEN ir.FirstAssignedDate !=NULL THEN ir.firstassigneddate else GETDATE() END
WHEN WI.Id like 'SR%' then CASE WHEN sr.firstassigneddate !=NULL THEN Sr.firstassigneddate else GETDATE() END
END),CASE
WHEN WI.Id like 'IR%' then CASE WHEN ir.FirstAssignedDate !=NULL THEN ir.firstassigneddate else GETDATE() END
WHEN WI.Id like 'SR%' then CASE WHEN sr.firstassigneddate !=NULL THEN Sr.firstassigneddate else GETDATE() END
END)))-48*DATEDIFF(wk,wi.CreatedDate,CASE
WHEN WI.Id like 'IR%' then CASE WHEN ir.FirstAssignedDate !=NULL THEN ir.firstassigneddate else GETDATE() END
WHEN WI.Id like 'SR%' then CASE WHEN sr.firstassigneddate !=NULL THEN Sr.firstassigneddate else GETDATE() END
END)
END)
from WorkItemDimvw WI
Left Outer Join IncidentDimvw IR on WI.EntityDimKey=IR.EntityDimKey
Left Outer Join ServiceRequestDimvw SR on WI.EntityDimKey=SR.EntityDimKey
Left Outer Join ChangeRequestDimvw CR on WI.EntityDimKey=CR.EntityDimKey
WHERE (wi.Id like 'IR%' or WI.ID like 'SR%') AND
((IR.ResolvedDate >=#StartDate AND IR.ResolvedDate < #EndDate) OR
(Sr.CompletedDate >=#StartDate AND SR.CompletedDate < #EndDate))

After many more hours of tweaking I've come up with the following which I'm 90% sure is right. If there is any way of optimising the query that would be helpful.
Declare #StartDate datetime
Declare #EndDate datetime
Set #StartDate = '2016/01/01'
Set #EndDate = '2016/12/31'
SELECT
WIAvgAssign = AVG(
Case
When id Like 'IR%' Then DATEDIFF(hour,NormalizedCreatedDate,NormalizedIRAssignedDate)
-(DATEDIFF(wk,normalizedcreateddate,NormalizedIRAssignedDate)*48)
-((DATEDIFF(day,normalizedcreateddate,NormalizedIRAssignedDate)-(DATEDIFF(wk,normalizedcreateddate,NormalizedIRAssignedDate)*2))*14)
-(Case When DateName(dw,NormalizedCreatedDate) = 'Sunday' THEN 24 ELSE 0 END)
-(Case When DATENAME(dw,NormalizedIRAssignedDate) = 'Saturday' THEN 24 ELSE 0 END)
When id Like 'SR%' Then DATEDIFF(hour,NormalizedCreatedDate,NormalizedSRAssignedDate)
-(DATEDIFF(wk,normalizedcreateddate,NormalizedSRAssignedDate)*48)
-((DATEDIFF(day,normalizedcreateddate,NormalizedSRAssignedDate)-(DATEDIFF(wk,normalizedcreateddate,NormalizedSRAssignedDate)*2))*14)
-(Case When DateName(dw,NormalizedCreatedDate) = 'Sunday' THEN 24 ELSE 0 END)
-(Case When DATENAME(dw,NormalizedSRAssignedDate) = 'Saturday' THEN 24 ELSE 0 END)
When id Like 'CR%' Then DATEDIFF(hour,NormalizedCreatedDate,NormalizedCRAssignedDate)
-(DATEDIFF(wk,normalizedcreateddate,NormalizedCRAssignedDate)*48)
-((DATEDIFF(day,normalizedcreateddate,NormalizedCRAssignedDate)-(DATEDIFF(wk,normalizedcreateddate,NormalizedCRAssignedDate)*2))*14)
-(Case When DateName(dw,NormalizedCreatedDate) = 'Sunday' THEN 24 ELSE 0 END)
-(Case When DATENAME(dw,NormalizedCRAssignedDate) = 'Saturday' THEN 24 ELSE 0 END)
END),
IRAvgAssign = AVG(DATEDIFF(hour,NormalizedCreatedDate,NormalizedIRAssignedDate)
-(DATEDIFF(wk,normalizedcreateddate,NormalizedIRAssignedDate)*48)
-((DATEDIFF(day,normalizedcreateddate,NormalizedIRAssignedDate)-(DATEDIFF(wk,normalizedcreateddate,NormalizedIRAssignedDate)*2))*14)
-(Case When DateName(dw,NormalizedCreatedDate) = 'Sunday' THEN 24 ELSE 0 END)
-(Case When DATENAME(dw,NormalizedIRAssignedDate) = 'Saturday' THEN 24 ELSE 0 END)),
SRAvgAssign = AVG(DATEDIFF(hour,NormalizedCreatedDate,NormalizedSRAssignedDate)
-(DATEDIFF(wk,normalizedcreateddate,NormalizedSRAssignedDate)*48)
-((DATEDIFF(day,normalizedcreateddate,NormalizedSRAssignedDate)-(DATEDIFF(wk,normalizedcreateddate,NormalizedSRAssignedDate)*2))*14)
-(Case When DateName(dw,NormalizedCreatedDate) = 'Sunday' THEN 24 ELSE 0 END)
-(Case When DATENAME(dw,NormalizedSRAssignedDate) = 'Saturday' THEN 24 ELSE 0 END)),
CRAvgAssign = AVG(DATEDIFF(hour,NormalizedCreatedDate,NormalizedCRAssignedDate)
-(DATEDIFF(wk,normalizedcreateddate,NormalizedCRAssignedDate)*48)
-((DATEDIFF(day,normalizedcreateddate,NormalizedCRAssignedDate)-(DATEDIFF(wk,normalizedcreateddate,NormalizedCRAssignedDate)*2))*14)
-(Case When DateName(dw,NormalizedCreatedDate) = 'Sunday' THEN 24 ELSE 0 END)
-(Case When DATENAME(dw,NormalizedCRAssignedDate) = 'Saturday' THEN 24 ELSE 0 END))
FROM (
Select WI.id,
CASE
WHEN wi.CreatedDate < DATEADD(HOUR, 9, CAST(CAST(wi.CreatedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 9, CAST(CAST(wi.CreatedDate AS DATE) AS DATETIME))
ELSE wi.CreatedDate
END NormalizedCreatedDate,
CASE
WHEN IR.FirstAssignedDate !=NULL THEN CASE
WHEN IR.FirstAssignedDate > DATEADD(HOUR, 17, CAST(CAST(IR.FirstAssignedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(IR.FirstAssignedDate AS DATE) AS DATETIME))
ELSE IR.FirstAssignedDate END
ELSE CASE WHEN IR.ResolvedDate > DATEADD(HOUR, 17, CAST(CAST(IR.ResolvedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(IR.ResolvedDate AS DATE) AS DATETIME))
ELSE IR.ResolvedDate END
END NormalizedIRAssignedDate,
CASE
WHEN SR.FirstAssignedDate !=NULL THEN CASE
WHEN SR.FirstAssignedDate > DATEADD(HOUR, 17, CAST(CAST(SR.FirstAssignedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(SR.FirstAssignedDate AS DATE) AS DATETIME))
ELSE SR.FirstAssignedDate END
ELSE CASE WHEN SR.CompletedDate > DATEADD(HOUR, 17, CAST(CAST(SR.CompletedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(SR.CompletedDate AS DATE) AS DATETIME))
ELSE SR.CompletedDate END
END NormalizedSRAssignedDate,
CASE
WHEN CR.FirstAssignedDate !=NULL THEN CASE
WHEN CR.FirstAssignedDate > DATEADD(HOUR, 17, CAST(CAST(CR.FirstAssignedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(CR.FirstAssignedDate AS DATE) AS DATETIME))
ELSE CR.FirstAssignedDate END
ELSE CASE WHEN CR.ActualEndDate > DATEADD(HOUR, 17, CAST(CAST(CR.ActualEndDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(CR.ActualEndDate AS DATE) AS DATETIME))
ELSE CR.ActualEndDate END
END NormalizedCRAssignedDate
from WorkItemDimvw WI
Left Outer Join IncidentDimvw IR
on WI.EntityDimKey=IR.EntityDimKey
Left Outer Join ServiceRequestDimvw SR
on WI.EntityDimKey=SR.EntityDimKey
Left Outer Join ChangeRequestDimvw CR
on WI.EntityDimKey=CR.EntityDimKey
Where (
(IR.ResolvedDate >= #StartDate AND IR.ResolvedDate < #EndDate)
OR (SR.CompletedDate >= #StartDate AND SR.CompletedDate < #EndDate)
OR (CR.ActualEndDate >= #StartDate AND CR.ActualEndDate < #EndDate)
)
) dataset
Edit - obviously we weren't excluding the time after 5pm (it's between 8 and 6 in my example as that's what my customer wanted) so I added in a calculation to remove 14 hours for every day (apart from weekends) the item is open which has given me what I believe to be the exact figures

This has been an intriguing question for me. I assumed a few things in my approach to this one:
CreatedDate always happens before FirstAssignedDate
SET DATEFIRST 7 (changes weekday numbers if different)
That is is okay to filter out CreatedDate and FirstAssignedDate if they are on a weekend
Here's my approach and I'm sure that it's wildly inefficient, but it was my first idea:
SELECT
WIAvgAssign = AVG(
Case
When id Like 'IR%' Then DATEDIFF(hour,NormalizedCreatedDate,NormalizedIRAssignedDate)
When id Like 'SR%' Then DATEDIFF(hour,NormalizedCreatedDate,NormalizedSRAssignedDate)
When id Like 'SR%' Then DATEDIFF(hour,NormalizedCreatedDate,NormalizedCRAssignedDate)
END
),
IRAvgAssign = AVG(DATEDIFF(hour,NormalizedCreatedDate,NormalizedIRAssignedDate)),
SRAvgAssign = AVG(DATEDIFF(hour,NormalizedCreatedDate,NormalizedSRAssignedDate)),
CRAvgAssign = AVG(DATEDIFF(hour,NormalizedCreatedDate,NormalizedCRAssignedDate))
FROM (
Select WI.id,
CASE
WHEN wi.CreatedDate < DATEADD(HOUR, 9, CAST(CAST(wi.CreatedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 9, CAST(CAST(wi.CreatedDate AS DATE) AS DATETIME))
ELSE wi.CreatedDate
END NormalizedCreatedDate,
CASE
WHEN IR.FirstAssignedDate > DATEADD(HOUR, 17, CAST(CAST(IR.FirstAssignedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(IR.FirstAssignedDate AS DATE) AS DATETIME))
ELSE IR.FirstAssignedDate
END NormalizedIRAssignedDate,
CASE
WHEN SR.FirstAssignedDate > DATEADD(HOUR, 17, CAST(CAST(SR.FirstAssignedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(SR.FirstAssignedDate AS DATE) AS DATETIME))
ELSE SR.FirstAssignedDate
END NormalizedSRAssignedDate,
CASE
WHEN CR.FirstAssignedDate > DATEADD(HOUR, 17, CAST(CAST(CR.FirstAssignedDate AS DATE) AS DATETIME))
THEN DATEADD(HOUR, 17, CAST(CAST(CR.FirstAssignedDate AS DATE) AS DATETIME))
ELSE CR.FirstAssignedDate
END NormalizedCRAssignedDate
from WorkItemDimvw WI
Left Outer Join IncidentDimvw IR
on WI.EntityDimKey=IR.EntityDimKey
Left Outer Join ServiceRequestDimvw SR
on WI.EntityDimKey=SR.EntityDimKey
Left Outer Join ChangeRequestDimvw CR
on WI.EntityDimKey=CR.EntityDimKey
--AVOID SATURDAYS and SUNDAYS in result set
--Also assumes SET DATEFIRST 7
Where DATEPART(WEEKDAY,wi.CreatedDate) NOT IN (1,7)
AND DATEPART(WEEKDAY,IR.FirstAssignedDate) NOT IN (1,7)
AND DATEPART(WEEKDAY,SR.FirstAssignedDate) NOT IN (1,7)
AND DATEPART(WEEKDAY,CR.FirstAssignedDate) NOT IN (1,7)
AND(
(IR.ResolvedDate >= #StartDate AND IR.ResolvedDate < #EndDate)
OR (SR.CompletedDate >= #StartDate AND SR.CompletedDate < #EndDate)
OR (CR.ActualEndDate >= #StartDate AND CR.ActualEndDate < #EndDate)
)
) dataset
So I basically just check if the CreatedDate < 0900 of the same day and set the time to 0900 if that is the case, and then I check if FirstAssignedDate > 1700 of the same day and set the time to 1700 if that is the case. I also filtered out all of the CreatedDates and FirstAssignedDates if they were on a weekend.
EDIT:
I updated the my original post. I changed the date checks to use DATEADD rather than building a string and trying to convert the string to a DATETIME

Related

Create view with variable declaration defined by a case expression, generating a dynamic date table based on getdate() reference

I have static date table and a working query that I use to add references fields for comparison between financial periods, I would like to save as a view however the variable declaration is not permitted.
Query is shown below, the specific issues is with declaring "#this_qtr_month" and calculating "Is QTD". The variable determines [Num of Month in QTR] for today.
declare #this_qtr_month as int = case when month(getdate()) in (1,4,7,10) then 1
when month(getdate()) in (2,5,8,11) then 2
when month(getdate()) in (3,6,9,12) then 3
end
select *
,DATEDIFF(day,[Date],getdate()) as 'Days Aged'
,DATEDIFF(ww,[Date],getdate()) as 'Weeks Aged'
,DATEDIFF(qq,[Date],getdate()) as 'QTRs Aged'
,DATEDIFF(yy,[Date],getdate()) as 'Years Aged'
,case when DATEPART(dd,[Date]) <= DATEPART(dd,getdate()) then 'Y' else 'N' end as 'Is MTD'
,case when #this_qtr_month > [Num of Month in QTR] then 'Y'
when #this_qtr_month = [Num of Month in QTR] and DATEPART(dd,[Date]) <= DATEPART(dd,getdate()) then 'Y'
else 'N'
end as 'Is QTD'
,case when getdate() >= DATEFROMPARTS(year(getdate()), [Month Num], day(date_modified_LeapYear)) then 'Y' else 'N' end as 'Is YTD'
from Date_Table_Static
You could write that without a variable:
SELECT *,
DATEDIFF(DAY, [Date], GETDATE()) AS 'Days Aged',
DATEDIFF(ww, [Date], GETDATE()) AS 'Weeks Aged',
DATEDIFF(qq, [Date], GETDATE()) AS 'QTRs Aged',
DATEDIFF(yy, [Date], GETDATE()) AS 'Years Aged',
CASE
WHEN DATEPART(dd, [Date]) <= DATEPART(dd, GETDATE()) THEN
'Y'
ELSE
'N'
END AS 'Is MTD',
CASE
WHEN (CASE
WHEN MONTH(GETDATE()) IN ( 1, 4, 7, 10 ) THEN
1
WHEN MONTH(GETDATE()) IN ( 2, 5, 8, 11 ) THEN
2
WHEN MONTH(GETDATE()) IN ( 3, 6, 9, 12 ) THEN
3
END
) > [Num of Month in QTR] THEN
'Y'
WHEN (CASE
WHEN MONTH(GETDATE()) IN ( 1, 4, 7, 10 ) THEN
1
WHEN MONTH(GETDATE()) IN ( 2, 5, 8, 11 ) THEN
2
WHEN MONTH(GETDATE()) IN ( 3, 6, 9, 12 ) THEN
3
END
) = [Num of Month in QTR]
AND DATEPART(dd, [Date]) <= DATEPART(dd, GETDATE()) THEN
'Y'
ELSE
'N'
END AS 'Is QTD',
CASE
WHEN GETDATE() >= DATEFROMPARTS(YEAR(GETDATE()), [Month Num], DAY(date_modified_LeapYear)) THEN
'Y'
ELSE
'N'
END AS 'Is YTD'
FROM Date_Table_Static;
Or, since all you need with this view is a SELECT, you could write that as a Stored Procedure or TVF (Table Valued Function).
EDIT: I didn't read your expression before, it doesn't need to be that complex:
SELECT *,
DATEDIFF(DAY, [Date], GETDATE()) AS 'Days Aged',
DATEDIFF(ww, [Date], GETDATE()) AS 'Weeks Aged',
DATEDIFF(qq, [Date], GETDATE()) AS 'QTRs Aged',
DATEDIFF(yy, [Date], GETDATE()) AS 'Years Aged',
CASE
WHEN DATEPART(dd, [Date]) <= DATEPART(dd, GETDATE()) THEN
'Y'
ELSE
'N'
END AS 'Is MTD',
CASE
WHEN (Month(Getdate())-1)%3+1 > [Num of Month in QTR] THEN
'Y'
WHEN (Month(Getdate())-1)%3+1 = [Num of Month in QTR]
AND DATEPART(dd, [Date]) <= DATEPART(dd, GETDATE()) THEN
'Y'
ELSE
'N'
END AS 'Is QTD',
CASE
WHEN GETDATE() >= DATEFROMPARTS(YEAR(GETDATE()), [Month Num], DAY(date_modified_LeapYear)) THEN
'Y'
ELSE
'N'
END AS 'Is YTD'
FROM Date_Table_Static;

Function to exclude Saturdays and Sundays

I created a "Daily Sales Query" that captures all the Total Sales entered from the previous work day which runs Mon-Fri at 8AM.
Question is, if it is Monday today, how can I capture the records from Friday.
so that I can exclude weekends.
Because if it is Monday, the total sales displays 0 which actually makes sense because Sunday is a not a work day. Please assist.
See my current code:
SELECT
CONVERT(VARCHAR, DATEADD(dd, - 1, GETDATE()), 103) AS Date,
'Sales Orders' AS Type,
COUNT(o.SalesOrderID) AS Orders,
SUM(d.QtyOrdered) AS Chairs,
ISNULL(ROUND(SUM(d.ExtendedPrice), 2), 0) AS [Total Ex GST]
FROM
dbo.SalesOrder o
LEFT OUTER JOIN
dbo.SalesOrderDetails d ON o.SalesOrderID = d.SalesOrderID
WHERE
(o.EntryDate >= CONVERT(CHAR(8), DATEADD(dd, - 1, GETDATE()), 112))
AND (o.EntryDate < CONVERT(CHAR(8), GETDATE(), 112))
AND (o.CustomerID <> 187);
You can use datediff(dd,0,getdate()) % 7 = 0 to determine if the current date is a Monday regardless of any other server settings (this is because the zero date in SQL Server is 1900-01-01 which happens to be a Monday).
declare #start date;
declare #finish date;
set #start = dateadd(dd, case when datediff(dd,0,getdate()) % 7 = 0 then -3 else -1 end, getdate());
set #finish = dateadd(dd,1,#start);
select
#start, datename(weekday,#start)
, #finish, datename(weekday,#finish)
, datename(weekday,getdate())
;
So in your query I would use:
declare #start date;
declare #finish date;
set #start = dateadd(dd, case when datediff(dd,0,getdate()) % 7 = 0 then -3 else -1 end, getdate());
set #finish = dateadd(dd,1,#start);
SELECT
CONVERT(VARCHAR, #start, 103) AS Date,
'Sales Orders' AS Type,
COUNT(o.SalesOrderID) AS Orders,
SUM(d.QtyOrdered) AS Chairs,
ISNULL(ROUND(SUM(d.ExtendedPrice), 2), 0) AS [Total Ex GST]
FROM
dbo.SalesOrder o
LEFT OUTER JOIN
dbo.SalesOrderDetails d ON o.SalesOrderID = d.SalesOrderID
WHERE
o.EntryDate >= #start
AND o.EntryDate < #finish
AND o.CustomerID <> 187
;
If you use a case statement to determine how many days in the past you need to go e.g.
dateadd(dd, case when datepart(weekday,getdate()) = 1 then -3 else -1 end, getdate()) -- StartDate
dateadd(dd, case when datepart(weekday,getdate()) = 1 then -2 else 0 end, getdate()) -- EndDate
so your code would look like
SELECT
CONVERT(VARCHAR, dateadd(dd, case when datepart(weekday,getdate()) = 1 then -3 else -1 end, getdate()), 103) AS Date,
'Sales Orders' AS Type,
COUNT(o.SalesOrderID) AS Orders,
SUM(d.QtyOrdered) AS Chairs,
ISNULL(ROUND(SUM(d.ExtendedPrice), 2), 0) AS [Total Ex GST]
FROM
dbo.SalesOrder o
LEFT OUTER JOIN
dbo.SalesOrderDetails d ON o.SalesOrderID = d.SalesOrderID
WHERE
(o.EntryDate >= CONVERT(CHAR(8), dateadd(dd, case when datepart(weekday,getdate()) = 1 then -3 else -1 end, getdate()), 112))
AND (o.EntryDate < CONVERT(CHAR(8), dateadd(dd, case when datepart(weekday,getdate()) = 1 then -2 else 0 end, getdate()), 112))
AND (o.CustomerID <> 187);
PS: Do confirm that weekday 1 is Monday on your server.

SQL WHERE depending on day of week

I have a requirement to check records up to differing dates, depending on which day of the week it is currently.
On a Friday I need for it to look at the entire next week, until Sunday after next. On any other day it should check the current week, up until the coming Sunday.
I have the below currently but it's not working due to syntax error. Is it possible to do a CASE WHEN inside a WHERE clause?
WHERE
T0.[Status] IN ('R','P')
AND
CASE
WHEN DATEPART(weekday,GETDATE()) = '5'
THEN T0.[DueDate] >= GETDATE() AND <= DATEADD(day, 15 - DATEPART(weekday, GetDate()), GetDate())
WHEN DATEPART(weekday, GETDATE()) != '5'
THEN T0.[DueDate] >= GETDATE() AND <= DATEADD(DAY ,8- DATEPART(weekday, GETDATE()), GETDATE())
END
It's much easier to create this logic with a series of logical or and and operators:
WHERE
T0.[Status] IN ('R','P') AND
((DATEPART(weekday,GETDATE()) = '5' AND
T0.[DueDate] >= GETDATE() AND
T0.[DueDate] <= DATEADD(day, 15 - DATEPART(weekday, GetDate()), GetDate())) OR
(DATEPART(weekday,GETDATE()) != '5' AND
T0.[DueDate] >= GETDATE() AND
T0.[DueDate] <= DATEADD(DAY ,8- DATEPART(weekday,GETDATE()),GETDATE())
)
Your syntax is wrong, you are using a condition evaluation in the THEN clause instead of an assignemnet
WHEN DATEPART(weekday,GETDATE()) = '5' THEN Your_column1 ELSE your_column2 END
......
or a inner case
CASE
WHEN DATEPART(weekday,GETDATE()) = '5' THEN
CASE WHEN T0.[DueDate] >= GETDATE()
AND <= DATEADD(day, 15 - DATEPART(weekday, GetDate()), GetDate())
THEN Your_column1 ELSE your_column2
END
END
......

DATEDIFF between two dates, excluding two specific days

In Dubai, the standard weekend runs from Friday - Saturday rather than the traditional Saturday / Sunday.
I am trying to calculate the amount of working days between two given dates, and this is the code I have;
DATEDIFF(dd, DATEADD(hour, DATEDIFF(hh, getdate(), getutcdate()), #StartDate),
DATEADD(hour, DATEDIFF(hh, getdate(), getutcdate()), #EndDate)+1)
-
(
(DATEDIFF(wk, #StartDate, #EndDate) * 2
+(CASE WHEN DATENAME(dw, #StartDate) = 'Saturday' then 1 else 0 end)
+(CASE WHEN DATENAME(dw, #EndDate) = 'Friday' then 1 else 0 end)
))
)
However it is calculating the wrong amount of days. For example;
When the start date is 02-03-2016 and the end date is 02-06-2016 the returns as 4, but it should be 2.
When the start date is 02-03-2016 and the end date is 02-07-2016 the result is 3 which is correct.
The code below calculates the working days from your examples correctly. You can wrap it in a scalar function if you want.
declare #from date, #to date;
set #from = '2016-02-03';
set #to = '2016-02-06';
with dates(date)
as
(
select #from
union all
select dateadd(dd, 1, [date])
from dates
where [date] < #to
)
select count(*) [working days]
from (
select date, case when datename(dw, [date]) in ('Friday', 'Saturday') then 0 else 1 end as working
from dates) as dt
where dt.working = 1

Calculate date ranges

I am trying to calculate the items sold 90 days prior to 6/1/2009 and 90 days after 6/1/2009 with the query below. it shows some error. Would someone kindly edcuate me please???
SELECT
location,
SUM((CASE WHEN t.order_date DATEADD (DAY, -90, '6/1/2009') THEN t.Item ELSE NULL END) as Prior_Items,
SUM(CASE WHEN t.order_date DATEADD (DAY, 89, '6/1/2009') THEN t.Item ELSE NULL END) as Post_Items
ELSE NULL
END)
FROM mytable t
where date = '6/1/2009'
group by location
your WHEN condition is not properly formed.
CASE WHEN t.order_date DATEADD (DAY, -90, '6/1/2009') THEN t.Item ELSE NULL END
^^^^^^^^^^^^^^^^^^^^
most likely you want something like:
CASE WHEN t.order_date>=DATEADD (DAY, -90, '6/1/2009') THEN t.Item ELSE NULL END
^^
I assume you want something like this.
DECLARE #d DATETIME
SET #d = '20090106'
SELECT
location,
SUM(CASE WHEN t.order_date < #d and t.order_date > DATEADD (DAY, -90, #d) THEN t.Item END) as Prior_Items,
SUM(CASE WHEN t.order_date >=#d AND t.order_date < DATEADD (DAY, 89, #d) THEN t.Item END) as Post_Items
FROM mytable t
where t.order_date BETWEEN DATEADD (DAY, -90, #d) AND DATEADD (DAY, 89, #d)
group by location