How to make SSRS subscriptions Kick off on Business Day 3 of month - sql

I am trying to figure out how to use the Data-Driven Subscription portion of SSRS to fire out a report to a bunch of people via email on the third business day of the month.
I'm a bit new to SQL but am learning very quickly, this just happens to be out of my small realm of knowledge.
I do have a table full of days of months, what year, what month, days of the week and all of that in different date formats. I just can't figure it out, I feel it's within my grasp of understanding though.
So far this is what I have and I feel like this could be summarized into a different easier sql statement? More optimized I guess.
select distinct --(CASE --when day_of_week = (2,3,4,5,6) then dateadd(day,1,day_desc_01) --when day_of_week = (7) then dateadd(day,2,day_desc_01) else day_of_week end) as 'BD_Date' day_of_week , day_desc_01 , date from Company.dbo.Company_Calendar where year = 2023 and day_of_week not in (1,7) and date <> '1900-01-01' and day_weekday_ct = 1 and year = 2023
I just want it to return the 3rd business day of the month for every month. Then probably a statement that says if it is the 3rd business day, fire off the report, if not, do nothing. I hope this makes a little bit of sense? I could also be way off track on this and way in over my head.
Thank you for your time and help!

This is a generic exmaple, but you should be able to apply the logic to your company calendar table.
This query will simply give you all the 3rd business days in the month. It filters out weekends and public holidays (assuming you have some way of recording the public holidays in your table). Once the filters are applied, if just assigns a row number to each records within in each calendar year/month and the only returns those where it is 3.
There are some extra columns included for clarity.
You may be able to simplify this but I dont; know what your calendar table contains so this assumes it has just the date (TheDate) and a column to indicate PublicHoliday.
CREATE VIEW ThirdBusDay AS
SELECT
*
FROM (
SELECT
TheDate
, DayOfWeek = DATEPART(WeekDay, TheDate)
, TheYear = YEAR(TheDate)
, TheMonth = MONTH(TheDate)
, TheDay = DAY(TheDate)
, WorkingDayOfMonth = ROW_NUMBER() OVER(PARTITION BY YEAR(TheDate), MONTH(TheDate) ORDER BY TheDate)
FROM myCalendarTable
WHERE
DATEPART(WeekDay, TheDate) NOT IN (7,1) -- Filter out Saturday and Sunday, change this if system week start is not Sunday.
AND
PublicHoliday = 0 -- filter out public holidays etc..
) d
WHERE WorkingDayOfMonth = 3
So if CAST(GetDate() AS Date) exists in this view then you know you have to execute the report.

Related

Recurring Date Calculator SQL

I'm looking to create a recurring date calculator that will correspond to EVENTS on a specific calendar date. Each event has its own rule.
For example, for EVENT A rule is "Occurs Tuesday monthly with the start date Tuesday 9-17-2019. I'm using a time dimension table with every date populated until 2025. Using these dates I was using in the WHERE clause
WHERE dayname = 'tuesday' and ( DATEDIFF(DAY, '2019-09-17', Calendar_Date) % 28 ) = 0 to get monthly tuesdays.
But I'm running into issues when there are two 5 Tuesdays in a month. 3-3-2020 and 3-31-2020. Need date populated to be 4-7-2020 instead of 3-31-2020.
Can anyone help with a solution?
With your query, you're pretty close. All you need to do is to then sub-select
SELECT MIN(CalendarDate) AS CalendarDate
FROM (your query goes here) AS d
GROUP BY YEAR(CalendarDate), MONTH(CalendarDate);

Counting working days between two dates Oracle

I'm trying to write a query which can count the number of working days between a payment being received and being processed, I started playing around with this for payments received in December 2017;
select unique trunc(date_received),
(case when trunc(date_received) in ('25-DEC-17','26-DEC-17') Then 0 when
to_char(date_received,'D') <6 Then 1 else 0 end) Working_day
from payments
where date_received between '01-DEC-17' and '31-dec-17'
order by trunc(date_received)
But to be honest, I'm at a loss as to how to take it further and add in date_processed and count the number of working days between date_processed and date_received... Any help would be much appreciated...
Maybe not the most optimal, but it works quite nicely, and it's easy to incorporate more complicated checks, like holidays. This query first generates all dates between the two dates, and then lets you filter out all the days that 'don't count'.
In this implementation I filtered out only weekend days, but it's quite easy to add checks for holidays and such.
with
-- YourQuery: I used a stub, but you can use your actual query here, which
-- returns a from date and to date. If you have multiple rows, you can also
-- output some id here, which can be used for grouping in the last step.
YourQuery as
(
select
trunc(sysdate - 7) as FromDate,
trunc(sysdate) as ToDate
from dual),
-- DaysBetween. This returns all the dates from the start date up to and
-- including the end date.
DaysBetween as
(
select
FromDate,
FromDate + level - 1 as DayBetween,
ToDate
from
YourQuery
connect by
FromDate + level - 1 <= ToDate)
-- As a last step, you can filter out all the days you want.
-- This default query only filters out Saturdays and Sundays, but you
-- could add a 'not exists' check that checks against a table with known
-- holidays.
select
count(*)
from
DaysBetween d
where
trim(to_char(DAYINBETWEEN, 'DAY', 'NLS_DATE_LANGUAGE=AMERICAN'))
not in ('SATURDAY', 'SUNDAY');

SSRS. Workday Function

I'm trying to convert the below Excel formula into SSRS but having looked around I cannot seem to find a solution. I can calculate the number of working days between two dates but what I'm trying to do is add on a number of working days to a date. Essentially I don't have the 2nd date.
I guess it would be something along the lines of the DATEADD function?
=WORKDAY($A1,B$1)
Hope someone can help
Many thanks
Here is a tsql solution to add X Business Days to a date.
declare #calendar as table (theDate date, dayOfWeek varchar (10));
declare #startDate as date = '20170704';
declare #businessDaysToAdd as integer = 10;
insert into #calendar
select theDate
, datename(dw, theDate) dow
from
dbo.dateTable('20170701', '20170720') ;
with temp as (
select theDate
, dayOfWeek
, rank() over (order by theDate) theRank
from #calendar
where theDate > #startDate
and dayOfWeek not in ('Saturday', 'Sunday')
)
select * from temp
where theRank = #businessDaysToAdd;
Notes
dbo.DateTable is a table valued function that just happens to exist in the database I was using. In real life, you might have an actual calendar table of some sort.
This example does not include holidays.
This is only the start of the answer to the posted question. It only solves the problem of Essentially I don't have the 2nd date.
Type this into the expression for the textbox. (From SSRS 2008 Datediff for Working Days)
=(DateDiff(DateInterval.day,Parameters!STARTDATE.Value,Parameters!ENDDATE.Value)+1)
-(DateDiff(DateInterval.WeekOfYear,Parameters!STARTDATE.Value,Parameters!ENDDATE.Value)*2)
-(iif(Weekday(Parameters!STARTDATE.Value) = 7,1,0)
-(iif(Weekday(Parameters!ENDDATE.Value) = 6,1,0))-1)
Ok after much perseverance I managed to get what I wanted in both TSQL and SSRS. My objective was to measure Agent productivity so I didn’t want to count the weekend and this would be unfair. If a date fell on a weekend then I wanted it to jump to a Monday. Likewise if adding number of days onto a date went over a weekend in the future then I needed the incremented date to reflect this. For the end user (In SSRS) I wanted a leading edge (Like an Upside down triangle) so that if the date + number working days was in the future then set to NULL, showing a zero would look like no productivity which is incorrect.
First TSQL - My base query started with the following SO thread but after trying many of the options I was finding when the date fell on a Saturday or Sunday the solution did not work for me (I was unable to create functions due to permissions). However tweaking the below got me there and I dealt with Sunday specifically
Add business days to date in SQL without loops
SELECT
,DATEADD(WEEKDAY, (/*Your Working Days*//5)*7+(/*Your Working Days*/ % 5) +
(CASE WHEN DATEPART(WEEKDAY,/*Your Date*/) <>7 AND DATEPART(WEEKDAY,/*Your Date*/) + (/*Your Working Days*/ % 5) >5 THEN 2
WHEN DATEPART(WEEKDAY,/*Your Date*/) = 7 AND DATEPART(WEEKDAY,/*Your Date*/) + (/*Your Working Days*/ % 5) >5 THEN 1 ELSE 0 END), /*Your Date*/) AS [IncrementedDate]
FROM /*YourTable*/
Then for SSRS - The 2 key points here is that TSQL will divide as an integer if the source number is an integer so this needs to be handled in SSRS and secondly you need to set the first week day to Monday as part of the expression.
I put this expression into a Matrix with Date Created being my Row Group and Contact Working Days being my Column Group.
=DATEADD("W",(INT(ReportItems!ContactWorkingDays.Value/5))*7+(ReportItems!ContactWorkingDays.Value MOD 5) + IIF(DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) <> 7 AND (DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) + (ReportItems!ContactWorkingDays.Value MOD 5) >5),2,IIF(DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) = 7 AND (DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) + (ReportItems!ContactWorkingDays.Value MOD 5) >5),1,0)),ReportItems!DateCreated.Value)
This does not include holidays - I'm not too bothered at this stage and that is for a rainy day! :)

Get date for nth day of week in nth week of month

I have a column with values like '3rd-Wednesday', '2nd-Tuesday', 'Every-Thursday'.
I'd like to create a column that reads those strings, and determines if that date has already come this month, and if it has, then return that date of next month. If it has not passed yet for this month, then it would return the date for this month.
Expected results (on 4/22/16) from the above would be: '05-18-2016', '05-10-2016', '04-28-2016'.
I'd prefer to do it mathematically and avoid creating a calendar table if possible.
Thanks.
Partial answer, which is by no means bug free.
This doesn't cater for 'Every-' entries, but hopefully will give you some inspiration. I'm sure there are plenty of test cases this will fail on, and you might be better off writing a stored proc.
I did try to do this by calculating the day name and day number of the first day of the month, then calculating the next wanted day and applying an offset, but it got messy. I know you said no date table but the CTE simplifies things.
How it works
A CTE creates a calendar for the current month of date and dayname. Some rather suspect parsing code pulls the day name from the test data and joins to the CTE. The where clause filters to dates greater than the Nth occurrence, and the select adds 4 weeks if the date has passed. Or at least that's the theory :)
I'm using DATEFROMPARTS to simplify the code, which is a SQL 2012 function - there are alternatives on SO for 2008.
SELECT * INTO #TEST FROM (VALUES ('3rd-Wednesday'), ('2nd-Tuesday'), ('4th-Monday')) A(Value)
SET DATEFIRST 1
;WITH DAYS AS (
SELECT
CAST(DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),N.Number) AS DATE) Date,
DATENAME(WEEKDAY, DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),N.Number)) DayName
FROM master..spt_values N WHERE N.type = 'P' AND N.number BETWEEN 0 AND 31
)
SELECT
T.Value,
CASE WHEN MIN(D.Date) < GETDATE() THEN DATEADD(WEEK, 4, MIN(D.DATE)) ELSE MIN(D.DATE) END Date
FROM #TEST T
JOIN DAYS D ON REVERSE(SUBSTRING(REVERSE(T.VALUE), 1, CHARINDEX('-', REVERSE(T.VALUE)) -1)) = D.DayName
WHERE D.Date >=
DATEFROMPARTS(
YEAR(GETDATE()),
MONTH(GETDATE()),
1+ 7*(CAST(SUBSTRING(T.Value, 1,1) AS INT) -1)
)
GROUP BY T.Value
Value Date
------------- ----------
2nd-Tuesday 2016-05-10
3rd-Wednesday 2016-05-18
4th-Monday 2016-04-25

Createing a report using financial periods

I have created a report for management that will total everything up by month with in a date range. Management has now decided that rather than by month they would like to go by period. We have 13 periods in a year each is 28 days except the last one is 29 or 30 depending on if its a leap year. The beginning of the first period is always 1-1-YYYY. So now I will need to figure out what the beginning and end of each period is and total up each period. I am not really sure how to do this since every year the dates will change and they may want to look at periods from the previous year through the current period. The code and results I am currently using are enclosed
SELECT
DATEADD(MONTH, DATEDIFF(MONTH, 0, finspecteddate), 0) AS 'Date'
,COUNT(*) AS Lots
,sum(flotSize) as 'Lot Size'
,sum(LReject) 'Lots Rejected'
,sum(fnumreject) as Rejected
,sum(fsampleSize) as 'Sample Size'
,sum(BDueDate) as 'Before Due Date'
FROM
ReportData
WHERE
finspecteddate >= '01-01-2014'
AND finspecteddate <= '10-15-2014'
GROUP BY
DATEADD(MONTH, DATEDIFF(MONTH, 0, finspecteddate), 0)
ORDER BY
date
Modify the following queries to suit your needs:
;WITH Period AS (
SELECT 1 AS ReportingPeriod,
CAST('2013-01-01' AS datetime) AS PeriodStartDate,
CAST('2013-01-28' AS datetime) AS PeriodEndDate
UNION ALL
SELECT CASE
WHEN p.ReportingPeriod = 13 THEN 1
ELSE p.ReportingPeriod + 1
END,
CASE
WHEN p.ReportingPeriod = 13 THEN DATEADD(YEAR,YEAR(p.PeriodStartDate)-1899,'1900-01-01')
ELSE DATEADD(DAY,28,p.PeriodStartDate)
END,
CASE
WHEN p.ReportingPeriod = 12 THEN DATEADD(YEAR,YEAR(p.PeriodStartDate)-1900,'1900-12-31')
ELSE DATEADD(DAY,28,p.PeriodEndDate)
END
FROM Period p
WHERE p.PeriodStartDate < '2017-12-03'
)
SELECT
P.PeriodStartDate
,P.PeriodEndDate
,COUNT(*) AS Lots
,sum(flotSize) as 'Lot Size'
,sum(LReject) 'Lots Rejected'
,sum(fnumreject) as Rejected
,sum(fsampleSize) as 'Sample Size'
,sum(BDueDate) as 'Before Due Date'
FROM
ReportData R
INNER JOIN Period P ON R.finspecteddate >= P.PeriodStartDate AND R.finspecteddate <= P.PeriodEndDate
WHERE
finspecteddate >= '01-01-2014'
AND finspecteddate <= '10-15-2014'
GROUP BY
P.PeriodStartDate
,P.PeriodEndDate
ORDER BY
P.PeriodStartDate
It uses a recursive CTE to build a period table, which is then joined to ReportData to aggregate asccording to your requirements. I don't have SQL Server 2005 to test it on. It works with 2008. Post a SQL Fiddle if you need help in 2005.
If you haven't got one, create a period calendar table with a year, period number, start date and end date columns. Then when you need to refer to periods, you can refer to the table. When they change the definition of what a period is, you can change the table. When they decide that February 29 doesn't count as one of the 28 days, you can change the table. When they decide to use the first Monday instead of the first Thursday as the start of the year, you just change the table. And best of all, changing how next year works won't change how last year works.
Then you just join to the table to determine which period you're in.