SQL Query to Count Number of Days, Excluding Holidays/Weekends - sql

I have a "workDate" field and a "receivedDate" field in table "tblExceptions." I need to count the number of days beteen the two. workDate always comes first - so, in effect, it's kind of like workDate is "begin date" and receivedDate is "end date". Some exclusions make it tricky to me though:
First, I need to exclude holidays. i do have a table called "tblHolidays", with one field - holidayDate. I have holidays stored up through next year, so maybe I can incorporate that into the query?
Also, most flummoxing is that work dates can never occur on weekends, but received dates can. So, i somehow need to exclude weekends when i'm counting, but allow for a weekend if the received date happens to fall on a saturday or sunday. so, if the work date is June 3rd, 2011, and received date is June 11th, 2011, the count of valid days would be 7, not 9.
Any help on this is much appreciated. Thanks!

Something like this should give you the number of days with the holidays subtracted:
select
days = datediff(day, workDate, receivedDate)
- (select count(*) from tblHolidays where holidayDate >= workDate and holidayDate < receivedDate)
from
tblExceptions
Note that the date functions differ between database systems. This is based on MS SQL Server, so it may need adapting if you are using some other database.

If you have a table full of dates to include (non-weekends, non-holidays, etc.) and you knew when the 'begin' date and the 'end' date is, then you can do something roughly like this:
select count(*) from tblIncludedDates where beginDateValue <= dateField and endDateValue >= dateField
to get the number of valid days between those dates.

Related

SQL - filter values based on month & date

I'm currently strugeling to get something done.
I needed only the rows where the date is between a certain date and month.
Example show only the rows where the date is between 01/05 (DD/MM) and 08/07 (DD/MM) the date can be found in the table tasks within the field information.
The year can't make any sense, but the results may only between those two dates in that year.
I've tried:
BETWEEN (TO_DATE ('01/05','DD/MM') AND (TO_DATE('08/07', 'DD/MM')
EXTRACT (DD/MM) from information.
none of those are working for me, I hope that someone of you can help me to figure this out!.
Thanks!
You seem to want to disregard the year. If so, then I would recommend:
TO_CHAR(datecol, 'MM/DD') BETWEEN '05/01' AND '07/08'
In order for BETWEEN to work in this case, you need the format in the order of MM-DD.
If you want this for a particular year, then use direct date comparisons:
datecol >= DATE '2018-05-01' AND
datecol < DATE '2018-07-09' -- note this is one day later
Oracle dates have a time component, so you need to be careful when making comparisons.

Wrong US week number calculation for 1st jan using datepart

SQL server DATEPART function has two options to retrieve week number;
ISO_WEEK and WEEK. I Know the difference between the two, I want to have week numbers based on Sunday start standard as followed in the US; i.e. WEEK. But it doesn't handles partial weeks the way I expected. e.g.
SELECT DATEPART(WEEK,'2015-12-31') --53
SELECT DATEPART(WEEK,'2016-01-01') --1
SELECT DATEPART(WEEK,'2016-01-03') --2
gives two different week numbers for a single week, divided in two years. I wanted to implement something like in the following link for week days.
Week numbers according to US standard
Basically I would like something like this;
SELECT DATEPART(WEEK,'2015-12-31') --1
SELECT DATEPART(WEEK,'2016-01-01') --1
SELECT DATEPART(WEEK,'2016-01-03') --2
EDIT:
Basically I am not good with the division of a single week into two, I have to perform some calculations based on week numbers and the fact that a single week to be divided isn't acceptable. So if above isn't possible.
Is it possible that the week number one would start from 2016-01-03. i.e. what I would in that case would be something like this:
SELECT DATEPART(WEEK,'2015-12-31') --53
SELECT DATEPART(WEEK,'2016-01-01') --53
SELECT DATEPART(WEEK,'2016-01-03') --1
If you want the US numbering, you can do this by taking the WEEK number of the end of the week rather than the date itself.
First ensure that the setting for first day of the week is in fact Sunday on your system. You can verify this by running SELECT ##DATEFIRST; this should return 7 for Sunday. If it doesn't, run SET DATEFIRST 7; first.
SELECT
end_of_week=DATEADD(DAY, 7-(DATEPART(WEEKDAY, '20151231')), '20151231'),
week_day=DATEPART(WEEK, DATEADD(DAY, 7-(DATEPART(WEEKDAY, '20151231')), '20151231'));
Which will return 2016/01/02 - 1.
If you wish generate week number of a date, it will return the week number of the year(input date)
Thus, I think sql server treat '2015-12-31' as the last week of 2015.

Calculating orders placed on the end of the month

I'm currently studying SQL Server using the book Ben-Gan, Itzik. T-SQL Fundamentals. Below is a query used to select order placed at end of the month. (I know that function EOMONTH() can also be used)
SELECT orderid, orderdate, custid, empid
FROM Sales.Orders
WHERE orderdate = DATEADD( month, DATEDIFF( month, '18991231', orderdate), '18991231');
The author's explanation is:
This expression first calculates the difference in terms of whole
months between an anchor last day of some month (December 31, 1899, in
this case) and the specified date. Call this difference diff. By
adding diff months to the anchor date, you get the last day of the
target month.
However, I'm still a bit confused as to how it actually works. Would someone kindly explain it?
That seems like a rather arcane way to do this. What the code is doing is calculating the number of months since the last day of some month. Then, it adds this number of months to that date. Because of the rules of dateadd(), the month remains the last date.
However, I prefer a simpler method:
where day(dateadd(day, 1, orderdate)) = 1
I find this much clearer.
select DATEDIFF(MONTH, '20160131', '20160201')
give us 1 month and
SELECT DATEADD(month, 1, '20160131')
give us 2016-02-29 00:00:00.000
that's ok
I tried out the query myself and seem to have got the hang of it. here is what i wrote just in case anyone else is interested
SELECT DATEADD(month, DATEDIFF(MONTH, '20160131', '20160201'), '20160131');
result:
2016-02-29 00:00:00.000
so my interpretation is that adding one or more "month" to a particular date in which the last date of the month is 31 will always return a date in which the date is the last day of the month. if this sentence makes any sense...

Get the month and year now then count the number of rows that are older then 12 months in SQL/Classic ASP

I know this one is pretty easy but I've always had a nightmare when it comes to comparing dates in SQL please can someone help me out with this, thanks.
I need to get the month and year of now then compare it to a date stored in a DB.
Time Format in the DB:
2015-08-17 11:10:14.000
I need to compare the month and year with now and if its > 12 months old I will increment a count. I just need the number of rows where this argument is true.
I assume you have a datetime field.
You can use the DATEDIFF function, which takes the kind of "crossed boundaries", the start date and the end date.
Your boundary is the month because you are only interested in year and month, not days, so you can use the month macro.
Your start time is the value stored in the table's row.
Your end time is now. You can get system time selecting SYSDATETIME function.
So, assuming your table is called mtable and the datetime object is stored in its date field, you simply have to query:
SELECT COUNT(*) FROM mtable where DATEDIFF(month, mtable.date, (SELECT SYSDATETIME())) > 12

T-SQL absence by month from start date end date

I have an interesting query to do and am trying to find the best way to do it. Basically I have an absence table in our personnel database this records the staff id and then a start date and end date for the absence. End date being null if not yet entered (not returned). I cannot change the design.
They would like a report by month on number of absences (12 month trend). With staff being off over the month change it obviously may be difficult to calculate.
e.g. Staff off 25/11/08 to 05/12/08 (dd/MM/yy) I would want the days in November to go into the November count and the ones in December in the December count.
I am currently thinking in order to count the number of days I need to separate the start and end date into a record for each day of the absence, assigning it to the month it is in. then group the data for reporting. As for the ones without an end date I would assume null is the current date as they are presently still absent.
What would be the best way to do this?
Any better ways?
Edit: This is SQL 2000 server currently. Hoping for an upgrade soon.
I have had a similar issue where there has been a table of start/end dates designed for data storage but not for reporting.
I sought out the "fastest executing" solution and found that it was to create a 2nd table with the monthly values in there. I populated it with the months from Jan 2000 to Jan 2070. I'm expecting it will suffice or that I get a large pay cheque in 2070 to come and update it...
DECLARE TABLE months (start DATETIME)
-- Populate with all month start dates that may ever be needed
-- And I would recommend indexing / primary keying by start
SELECT
months.start,
data.id,
SUM(CASE WHEN data.start < months.start
THEN DATEDIFF(DAY, months.start, data.end)
ELSE DATEDIFF(DAY, data.start, DATEADD(month, 1, months.start))
END) AS days
FROM
data
INNER JOIN
months
ON data.start < DATEADD(month, 1, months.start)
AND data.end > months.start
GROUP BY
months.start,
data.id
That join can be quite slow for various reasons, I'll search out another answer to another question to show why and how to optimise the join.
EDIT:
Here is another answer relating to overlapping date ranges and how to speed up the joins...
Query max number of simultaneous events