SQL Date Diff Business Days [duplicate] - sql

This question already has answers here:
Count work days between two dates
(24 answers)
Closed 6 years ago.
I need to count all orders that have a datediff <= 1. I use the COALESCE function, because sometimes the Date1 can be null.
SELECT COUNT(*)
FROM Orders
WHERE DATEDIFF(dd,COALESCE(Date1, Date2),Date0) <= 1
Is there a way I can count only the business days (Mon-Fri)?
Thanks.

You could change your count to a conditional sum, using DATEPART to ignore the Saturdays and Sundays (which should have a dw of 7 & 1 respectively).
SELECT SUM(CASE WHEN DATEPART(dw, COALESCE(Date1, Date2)) BETWEEN 2 AND 6
THEN 1 ELSE 0 END)
FROM Orders
WHERE DATEDIFF(dd,COALESCE(Date1, Date2),Date0) <= 1

You can use a Calendar table and store all business days in it.
Or, you can use the following simple formula to calculate number of business days between two dates. The formula assumes that Saturday and Sunday are not business days. It assumes that two given dates are business days.
All it does, is calculates the normal difference in days and then subtracts 2 (non-business) days from this result for each beginning of the week.
Example 1
DECLARE #Date0 date = '2016-04-07'; -- Thursday
DECLARE #Date1 date = '2016-04-08'; -- Friday
SELECT
DATEDIFF(day, #Date0, #Date1) -
DATEDIFF(week, #Date0, #Date1) * 2 AS BusinessDays;
Result
BusinessDays
1
Example 2
DECLARE #Date0 date = '2016-04-08'; -- Friday
DECLARE #Date1 date = '2016-04-11'; -- Monday
SELECT
DATEDIFF(day, #Date0, #Date1) -
DATEDIFF(week, #Date0, #Date1) * 2 AS BusinessDays;
Result
BusinessDays
1
Example 3
DECLARE #Date0 date = '2016-04-08'; -- Friday
DECLARE #Date1 date = '2016-04-18'; -- Monday
SELECT
DATEDIFF(day, #Date0, #Date1) -
DATEDIFF(week, #Date0, #Date1) * 2 AS BusinessDays;
Result
BusinessDays
6
Your query would look like this:
SELECT COUNT(*)
FROM Orders
WHERE
DATEDIFF(day, COALESCE(Date1, Date2), Date0) -
DATEDIFF(week, COALESCE(Date1, Date2), Date0) * 2 <= 1
;

Related

Return data 2 years back same month previous week with date range

I am trying to extract 2 years ago data with date range greater than 07/01/2019 and 2 years ago same month and week. Need suggestions on date conversion as well
select
tilr.BusinessUnitID
,emph.employeeID
,convert(varchar(10), cast(cast(tilr.date_key as varchar(10)) as date), 101) as ConvertDate
,tilr.paidhr as 'Paid hr'
from [dbo].[location] tilr
inner join [dbo].[Employee] emph
on emph.employeeID = tilr.employeeID
and emph.businessunitid = tilr.BusinessUnitID
and emph.date_key = tilr.date_key
where
tilr.date_key >= 20190701
and datename(year, convert(varchar(10), cast(cast(tilr.date_key as varchar(10))as date), 101))
< DateAdd(YY, -2, GETDATE())
Trying to get data for date range >= 07/01/2019 and < 10/23/2019 ( +/- days of same month 2 years ago) for comparison. With above query I'm getting data till end of the year 12/2019 instead of 10/2019.
Sample data
BusinessUnitID employeeID ConvertDate Paid hr
1234 1 07/01/2019 1.4
2345 2 10/25/2019 3.5
It looks like you need something like the following condition
tilr.date_key >= DATEADD(month, -2, DATEFROMPARTS( YEAR(GETDATE()) - 2, MONTH(GETDATE()), 1 )) AND
tilr.date_key < DATEADD(month, 1, DATEFROMPARTS( YEAR(GETDATE()) - 2, MONTH(GETDATE()), 1 ))
Note how calculations only use date functions, not conversion to/from varchar, and that there are no functions on the actual column value. This means that indexes can be used efficiently.

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())
)
)

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

On Monday pull data from Friday to Sunday, on other weekdays from prior day only

I have this query which is currently pulling all incidents from a SQL Server database which were closed on prior weekday. It's pretty neat as it's using modulo to be independent over ##DATEFIRST local settings. However I need to amend it in a way that on Mondays it gives me all incidents closed between Friday and Sunday.
Current code:
SELECT
inc.Incident_Id, inc.Close_Time
FROM
inc
WHERE
CONVERT (CHAR(10), inc.Close_Time, 126) = CONVERT (CHAR(10), (DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + ##DATEFIRST) % 7
WHEN 1 THEN -2
WHEN 2 THEN -3
ELSE -1
END, DATEDIFF(DAY, 0, GETDATE()))),126)
I tried using another CASE DATEPART(WEEKDAY, GETDATE()) before first CONVERT but it didn't work out as it looked like >= and <= (or BETWEEN & AND) are not allowed both in one condition after THEN.
To sum up it should be like this:
On Mondays - incidents closed between Friday and Sunday
On other weekdays - incidents closed on prior day
Try this:
DECLARE #from date =
DATEADD(day,
CASE datediff(d, 0, getdate()) %7
WHEN 0 THEN -3
WHEN 6 THEN -2
ELSE -1
END, getdate())
SELECT inc.Incident_Id, inc.Close_Time
FROM inc
WHERE
inc.Close_Time >= #from
AND inc.Close_Time < #to
Monday and Sunday will return friday and after
Tuesday to saturday will return the day before.

SQL Server 2008 Count(Distinct?

ApptStart
2005-02-18 10:00:00.000
2005-02-18 13:00:00.000
2005-02-18 11:00:00.000
2005-02-21 09:00:00.000
2005-02-18 15:30:00.000
2005-02-18 14:30:00.000
.
.
.
I have a column in our database that looks like the above. I want to count appointments for the month for a given doc. On Fridays most of them do a half day. So I do not want to count Fridays with appointments only in the morning. If the appointment is in the afternoon, after 12:00:00.000 I want to include that day in the distinct count.
So far I have:
SELECT
ScheduleDays = count(distinct CONVERT(datetime, convert(char(12), a.ApptStart, 1)))
FROM Appointments a
WHERE
ApptKind = 1 AND
--filter on current month
a.ApptStart >= ISNULL(DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0),'1/1/1900') AND
a.ApptStart < ISNULL(DATEADD(month, DATEDIFF(month, 0, GETDATE())+1, 0),'1/1/3000') AND
--Filter on doctor
a.ResourceID in (201)
This worked when I counted every day with appointments on it, but like I said I need to exclude those half days.So I was thinking about only looking at the last right chars of the ApptStart and comparing it x > noon in a case inside the distinct count...
I tried the following, but it did not work:
ScheduleDays = count(distinct case when (Right(a.ApptStart, 12)) > '12:00:00:000' then 1 else 0 END)
Thanks in advance!
EDIT
I tried:
SELECT
ScheduleDays=COUNT(DISTINCT(CAST(datediff(d,0,a.ApptStart) as datetime)))
FROM Appointments a
WHERE
ApptKind = 1 AND
--filter on current month
a.ApptStart >= ISNULL(DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0),'1/1/1900') AND
a.ApptStart < ISNULL(DATEADD(month, DATEDIFF(month, 0, GETDATE())+1, 0),'1/1/3000')AND
--filter all days that aren't Friday, and then give you all Fridays with an hour > 12.
DATENAME(weekday, a.ApptStart) <> 'Friday' OR DATEPART(hour, a.ApptStart) > 12 AND
--Filter on doctor
a.ResourceID in (201)
for 1808 as the count
You probably want to treat dates as dates, rather than strings. You can determine whether a particular timestamp is on a Friday -- or the hour of a timestamp -- using DATEPART, without having to CONVERT it into a CHAR:
datename(weekday, timestamp_value) -- returns Friday
datepart(weekday, timestamp_value) -- returns either 5 or 6, depending on the value of SET DATEFIRST. (Get day of week in SQL 2005/2008)
datepart(hour, timestamp_value) -- returns hour part
Using these, you can test whether a timestamp is on Friday at or after noon by checking if datepart(weekday, timestamp_value) = 6 and datepart(hour, timestamp_value) >= 12.
bendataclear pointed out that you're using distinct on a case statement which can only ever return 0 or 1, so your total will only ever be 0, 1, or 2. If you're trying to determine which days the doctors worked more than half a day, you'll need to select distinct dates --
SELECT COUNT(DISTINCT(CAST(datediff(d,0,timestamp_value) as datetime)))
FROM table_name
WHERE DATENAME(weekday, timestamp_value) <> 'Friday' OR DATEPART(hour, timestamp_value) > 12
AND the rest of your filters here
The WHERE clause there will give you all days that aren't Friday, and then give you all Fridays that have an hour > 12.