A calendar table is really going to help you out here. Assuming it has one record per calendar date, you can use this table to note weekends, holidays, fiscal periods vs Calendar periods, beginning of month/end of month dates. A number of things that can help simplify your date based queries.
See this question here for an example on creating a calendar table.
The main point is to create a data set with 1 record per date, with information about each date including Month, Day of Week, Holiday status, etc.
Without a calendar table, you can use database functions to generate your set of dates on the fly.
Getting the Month number for a date can be done with
extract([Month], <date field goes here> )
Getting a list of values from nothing will be required to generate your list of dates (if you don't have a calendar table with 1 record per date to use) will vary depending on your source database. In oracle I use a 'select from all_objects' type query to achieve this.
An example from Ask Tom:
select to_date(:start_date,'dd-mon-yyyy') + rownum -1
from all_objects
where rownum <=
to_date(:end_date,'dd-mon-yyyy')-to_date(:start_date,'dd-mon-yyyy')+1
For Sql Server refer to this stackoverflow question here.
Once you have a data set with your calendar type information, you can join it to your query above:
join mycalendar cal on cal.date >= c.PTOStartDate
and cal.date <= c.PTOEndDate
Also note, _add_days is a Cognos function. When building your source queries, try and use Native functions, like in oracle you can 'c.PTOStartDate + a.PTODays'. Mixing Cognos functions with native functions will sometime force parts of your queries to be processed locally on the Cognos server. Generally speaking, the more work that happens on the database, the faster your reports will run.
Once you have joined to the calendar data, you are going to have your records multiplied out so that you have 1 record per date. (You would not want to be doing any summary math on PTODays here, as it will be inflated.)
Now you can add clauses to track your rules.
where cal.Day_Of_Week between 2 and 6
and cal.Is_Holiday = 'N'
Now if you are pulling a specific month, you can add that to the criteria:
and cal.CalendarPeriod = '201508'
Or if you are covering a longer period, but wanting to report a summary per month, you can group by month.
Final query could look something like this:
select c.UserID, cal.CalendarPeriod, count(*) PTO_Days
from dbo.PTOCalendar c
join myCalendar cal on on cal.date >= c.PTOStartDate
and cal.date <= c.PTOEndDate
where cal.day_of_week between 2 and 6
and cal.Is_Holiday = 'N'
group by c.UserID, cal.CalendarPeriod
So if employee with UserID 1234 Took a 7 day vacation from thursday June 25th to Friday July 3th, that covered 9 days, the result you get here will be:
1234 201506 4
1234 201507 3
You can join these results to your final query above to track days off per month.