Background color based on two data dates - reporting-services

I am trying to color the background of the rows of the table in the report based on two dates. Here is the logic I am trying to get
if Date A < (Date B + 7 days) then I want the row to be Green
if Date A is greater than (Date B + 7 days) but less than (Date B + 14 days) then I want the row to be yellow
If Date A is greater than (Date B + 14 days) then I want the row to be red.
Date A and Date B are both fields in my report.

The SWITCH function will let you have multiple conditions with a results for each - like a CASE statement.
=SWITCH(Fields!DATE_A.Value <= DATEADD("d", 7, Fields!DATE_B.Value), "MintCream",
Fields!DATE_A.Value >= DATEADD("d", 14, Fields!DATE_B.Value), "MistyRose",
Fields!DATE_A.Value > DATEADD("d", 7, Fields!DATE_B.Value) AND Fields!DATE_A.Value < DATEADD("d", 14, Fields!DATE_B.Value), "Ivory",
1 = 1, "LightGrey")
The first (and every other) argument is the expression to be evaluated, the second is the value if true.
A 1 = 1 can be added as an evaluated expression as an ELSE for the SWITCH.
I usually use paler shades for background highlighting.

Related

Convert "YYYYWW" into month (SSRS)

I am creating a report and would like to retrieve data based on a date field (string) in the format YYYYWW. I want to filter the data so I retrieve the current month, previous month, the month before that and older values - using 4 different datasets.
For example:
201547 = November 2015
How do I create a calculated member which converts a string into the month name and year? I would like to use this value to filter out the data from the cube. Is there any other way of doing this?
:]1
Try adding a calculated field and set it to this expression:
=MonthName(Month(DateAdd("ww",CInt(MID("201547",5,LEN("201547")))
,DateSerial(CInt(LEFT("201547",4)),1,1)))) & " " & LEFT("201547",4)
Then use that field to filter your report.
Replace the string for the field returning "201547"
=MonthName(Month(DateAdd("ww",
CInt(MID(Fields!YearWeek.Value,5,LEN(Fields!YearWeek.Value)))
,DateSerial(CInt(LEFT(Fields!YearWeek.Value,4)),1,1))))
& " " & LEFT(Fields!YearWeek.Value,4)
UPDATE: MDX script for querying a calulated member with the required format:
I've tested with the following MDX:
WITH MEMBER [Measures].[month&year] AS
'FORMAT(DateAdd("ww",STRTOVALUE(MID("201547",5,LEN("201547"))) ,CDATE(DateSerial(LEFT("201547",4),1,1))),"MMMM") + " " + LEFT("201547",4)'
SELECT { [month&year] } ON COLUMNS
FROM [Your Cube]
To use it in your query replace "201547" for [Dimension].[Attribute].MemberValue that corresponds to your cube structure:
WITH MEMBER [Measures].[month&year] as
'FORMAT(DateAdd("ww",STRTOVALUE(MID([Dimension].[Attribute].MemberValue,5,LEN([Dimension].[Attribute].MemberValue)))
,CDATE(DateSerial(LEFT([Dimension].[Attribute].MemberValue,4),1,1))),"MMMM") + " " + LEFT([Dimension].[Attribute].MemberValue,4)'
SELECT
{ [Dimension].[Attribute].[Attribute] }
{[month&year]} ON COLUMNS
FROM [Your Cube]
Once you have this field in your dataset you can easily filter the values using a parameter.
Let me know if this can help you.
Using a combination of the resources found out on the internet you can find the information you require.
First you need to find the first day of the first week of the year. This has already been determined by this answer as
DateAdd("d",
(-1) * (CInt(New DateTime(Year(Now), 1, 1).DayOfWeek) +
IIf(CInt(New DateTime(Year(Now), 1, 1).DayOfWeek) < DayOfWeek.Monday,
7,
0)
) + 1,
New DateTime(Year(Now), 1, 1))
This needs to be adapted for any year - not just the current one by finding the year from the string as follows
CInt(Left(Parameters!myDate.Value,4))
Now, as noted in this resource you can use a DateAdd to add the number of weeks of the year you have entered to the first date of the year
=(DateAdd(DateInterval.WeekOfYear,
CInt(Right(Parameters!myDate.Value,2))-1,
<<FIRST_DAY_OF_YEAR>>)
You then want to get the month name of the month of this date, using Month and MonthName. Smashing it all together would result in the following
=MonthName(Month(DateAdd(DateInterval.WeekOfYear,
CInt(Right(Parameters!myDate.Value,2))-1,
DateAdd("d",
(-1) * (CInt(New DateTime(CInt(Left(Parameters!myDate.Value,4)), 1, 1).DayOfWeek) +
IIf(CInt(New DateTime(CInt(Left(Parameters!myDate.Value,4)), 1, 1).DayOfWeek) < DayOfWeek.Monday,
7,
0)
) + 1,
New DateTime(CInt(Left(Parameters!myDate.Value,4)), 1, 1))
)))
This will get a Textual value of the month for the interval
Create a new placeholder in the same textbox and then repeat the above for finding the year
=Year(DateAdd(DateInterval.WeekOfYear, ...
(Remember to remove the last brace otherwise you’ll get a End of Statement expected error.)
This shoud give what you require, so
201501 = December 2014
201547 = November 2015
201553 = December 2015
201622 = May 2016
Let me know if this helps, or if you have further questions
Part 1: Establishing which day falls into which week
ISO-8601 declares the international standards for converting dates into week numbers, and vice-versa.
ISO standard weeks start on a Monday. A year can have either 52 or 53 weeks.
There are 4 ways of establishing when Week 1 starts:
- It is the first week with a majority (4 or more) of its days in January.
- Its first day is the Monday nearest to 1 January.
- It has 4 January in it. Hence the earliest possible dates are 29 December through 4 January, the latest 4 through 10 January.
- It has the year's first working day in it - i.e. excluding Saturdays, Sundays and the 1st of January.
Part 2: Excel calculations
This answer assumes that the dates are being stored as 6-character strings.
First determine the year and what day of the week it starts on.
1) Strip the first four characters from the string.`
=left(<cell containing the year+week string>, 4)
2) Prepend "1/1/" to it.
="1/1/"&left(<cell containing the year+week string>, 4)
3) Convert this string to an Excel date
=datevalue(<the last result>)
4) Determine the Weekday of the 1st day of that year.
=weekday(<the last result>)
5) Calculate the Excel date of the first Monday.
=if((<the last result>-4)<0,<the result of step 3>+8-<the last result>, <the result of step 3>+1-<the last result>)
6) Work out how many weeks on from that we are:
=right(<original 6 char year/week string>,2)
7) Convert 6) to a number
=value(<last result>)
8) Add that to the Monday of Week 1
=<result of step 5>+<result of step 7>*7
9) Convert this to a month number
=month(<last result>)
10) Convert this to a month name
=choose(<last result>,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec")
11) Add the year back on
=<lastresult>&" "&<result of 1>
This gives the month number which contains the Monday of the current numbered week.
If cell A1 contains '201547
then cell B1 should contain:
=CHOOSE(MONTH(IF((WEEKDAY(DATEVALUE("1/1/"&LEFT(A1,4)))-4)<0,DATEVALUE("1/1/"&LEFT(A1,4))+1-WEEKDAY(DATEVALUE("1/1/"&LEFT(A1,4))),DATEVALUE("1/1/"&LEFT(A1,4))+8-WEEKDAY(DATEVALUE("1/1/"&LEFT(A1,4))))+7*(VALUE(RIGHT(A1,2)))),"January","February","March","April","May","June","July","August","September","October","November","December")&" "&LEFT(A1,4)
If A1 contains 201547 then B1 returns "November 2015".
Further considerations:
You may want to make it more sophisicated, so that a month ending in a Monday does not have the week commencing with its final Monday counted as part of the month. More generally, that week only counts as part of a month is 3 or more of the days are in the month. Or 3 or more of its working days are part of the month.
As it is, I would sort with the calculated month and year as primary key and the YYYYMM code as secondary key.

Query/Expression for Previous Month

Used as an expression in Access 2010, the below returns, for example, AUG15.
Left(MonthName(Month(Date())),3) & Right(Year(Date()),2)
How do I modify this to return the previous month, i.e. JUL15?
Start from the DateAdd expression which #Sam suggested ...
? DateAdd("m", -1, Date())
7/13/2015
Next use Format to present it as 3-letter month plus 2-digit year ...
? Format(DateAdd("m", -1, Date()), "mmmyy")
Jul15
If you want the month in all caps, feed the previous expression to UCase ...
? UCase(Format(DateAdd("m", -1, Date()), "mmmyy"))
JUL15
Note those examples are from the Access Immediate window, but those expressions (without ?) will work the same in your query.
You should look at the DateAdd function:
DateAdd ( interval, number, date )
Depending on your exact requirements, you could use it to substract a month from the current date like so:
DateAdd(m, -1, Date())
...or to build upon your expression:
Left(MonthName(Month(DateAdd(m, -1, Date()))),3) & Right(Year(DateAdd(m, -1, Date())),2)
to get records on same day of last month,eg. today is 19/12/21,and get records on 19/11/21 , you can use parameter query and enter the date required.
If every records of last month, ie from 1/11/21 to 30/11/21, two columns in query should be created to identify the month and year required. Make it clear,2 columns in query m:month(date()) and y:year(date()) and in criteria row put criteria of month and year required. If for last month criteria for m column is IIF(month(date())=1,12,month(date())-1), for y column is IIf(month(date())=1,year(date())-1,year(date())).
IIF is for when current date is in January.

SSRS Charts data

I have situation where I need to create a column chart.
I have a field NotificationLog.Duedate . With this due date I need to create a chart with various condition.
I need to calculate the count of rows with conditions like below
NotificationLog.Duedate < Present date
NotificationLog.Duedate > Present date & NotificationLog.DueDate-Present date < 8 days
NotificationLog.Duedate > Present date & NotificationLog.DueDate-Present date > 8 days
Using the above counts I need to create a column Chart which with the three categories in X axis and Days marked in Y axis.
As of now I get the NotificatonLog.Duedate in a dataset with several other columns . How Can i proceed from this point and accomplish my requirement .
Thanks !
You need to set up an approriate expression-based field to group on.
I have a simplified Dataset to replicate your issue:
I have added a Calculated Field to the Dataset, called DuedateGroup:
The expression is:
=Switch(Fields!Duedate.Value < Today(), "Overdue"
, Fields!Duedate.Value > Today() and Fields!Duedate.Value < DateAdd(DateInterval.Day, 8, Today()), "Near Due"
, Fields!Duedate.Value > Today() and Fields!Duedate.Value > DateAdd(DateInterval.Day, 8, Today()), "Far Due")
i.e. the three groupings you require.
Now you can just use the new field in the Chart:
Looks OK to me.
If you didn't want to set up a Calculated Field, you could add the group expression directly into the Category Group at the Chart level, but I like the Calculated Field option.

How do I match a month range in the database to two dates?

Assume I have a table that contains a from_month (int, 1-12) and a to_month (int, 1-12) column, and I then have another table that contains a from (int, unix timestamp) and to (int, unix timestamp) column.
How would I match rows where the from_month and to_month columns contain my from and to timestamps, taking into account year boundaries on either side?
Scenario:
With from_month as 11 and to_month as 2, is there a way where I can get a from value of 1383264000 and a to value of 1391212800 to match?
At the same time however:
With from_month as 3 and to_month 8, is there a way where I can get a from value of 1362096000 and a to value of 1375315200 to match?
Clarifications:
I need records from the second table where the months from both timestamps fall between the range set out from the first table.
Also, I can obtain the month from the timestamp, so it's not necessary for MySQL to parse it, but the solution is likely unaffected.
Sorry but i'm not sure how you want to compare with the year
But if only month, you can use FROM_UNIXTIME to get date from a unixtime, and MONTH to get month from a date
for example
SELECT FROM_UNIXTIME(1391212800)
> February, 01 2014 00:00:00+0000
SELECT MONTH(FROM_UNIXTIME(1391212800))
> 2
with the month get from unix time, I'm sure you can do the rest or help explain more detail what you want to.
Hope this help
Here is the SQL how to create unix timestamp from your input :
SELECT
#year:= YEAR(CURDATE()),
#from:= CONCAT(#year, '-', 11, '-1') AS from_date,
#to:= CONCAT(IF(11<=2, #year, #year+1), '-', 2, '-1') AS to_date,
UNIX_TIMESTAMP(#from) AS from_timestamp,
UNIX_TIMESTAMP(#to) AS to_timestamp;
Month 11 & 2 are hard-coded. I used variables, so the sql is shorter.
SQL Fiddle.
Your scenario is :
With from_month as 11 and to_month as 2, is there a way where I can get a from value of 1383264000 and a to value of 1391212800 to match?
Which is from 2013-11-01 00:00:00 to 2014-02-01 00:00:00. Are you sure you need TO date to be from first of the month? or the last day of the Februar?
A solution was found that does an inclusive month check using months as integers from 0-11.
# Filter
SET #Fs = 2; # Mar
SET #Fe = 7; # Aug
#
SET #Ps = 2; # Mar
SET #Pe = 4; # May
SELECT
(
(
MOD(#Pe - #Fs + 24, 12) <= MOD(#Fe - #Fs + 24, 12)
)
AND (
MOD(#Ps - #Fs + 24, 12) <= MOD(#Pe - #Fs + 24, 12)
)
)
OR MOD(#Fe - #Fs + 24, 12)=11;

Using DatePart() with date ranges crossing the datepart boundary

I am currently trying to summarise some data tables into a report. Each record in the table consists of a date range, something like this:
StartDate EndDate
--------------------
13/04/13 15/04/13
17/04/13 24/04/13
28/04/13 03/05/13
05/05/13 10/05/13
Assuming the date ranges signify something like days of leave, I want to be able to calculate the total amount of days of leave per month. I came across the DatePart function which seems to work apart from one edge case: when the date range crosses a month boundary. Since the DatePart function returns the month for one given date, I am no longer able to use that to determine the amount of days of leave for that edge case record (in the example above it is record 3), since it applies to two separate months.
Ideally I want my final table to look like:
Month #OfDays
--------------------
4 11 (1st record - 2, 2nd record - 7, 3rd record - 2)
5 8 (3rd record - 3, 4th record - 5)
I've considered some messy options, such as populating a temporary table having each record signifying a different day and then doing a query on that, but I am not sure how this ties in with a report. Right now my report record source is the (incorrect) query, is it possible to have a record source as a VBA function that returns a recordsource?
Another thing I thought was to possibly to have an initial query that splits up any edge cases into two seperate records, where the date range only covers one month, and then use that for my final grouping query. Is that even possible?
I feel there may be a much simpler solution to this problem yet I can't see it.
If anyone has any ideas it would be much appreciated!
To accomplish your task using Access queries you will need to create a table named [Numbers] with a single Number (Long Integer) column named [n] containing the numbers 1, 2, 3, ... up to the highest year you expect to be working with. I created mine as follows
n
----
1
2
3
...
2499
2500
You'll also need to paste the following VBA function into an Access Module
Public Function IsValidDayOfYear(YearValue As Long, DayValue As Long) As Boolean
Dim IsLeapYear As Boolean
If (YearValue Mod 400) = 0 Then
IsLeapYear = True
ElseIf (YearValue Mod 100) = 0 Then
IsLeapYear = False
ElseIf (YearValue Mod 4) = 0 Then
IsLeapYear = True
Else
IsLeapYear = False
End If
IsValidDayOfYear = (DayValue <= IIf(IsLeapYear, 366, 365))
End Function
Let's assume that your source table is called [DateRanges]. We'll start by creating a query that generates every day of the year for each year represented in the source table. The trick here is that DateSerial() "rolls over" month boundaries, so
DateSerial(2013, 1, 32) = #2013-02-01#
and
DateSerial(2013, 1, 234) = #2013-08-22#
SELECT DateSerial(yr.n, 1, dy.n) AS [Date]
FROM Numbers yr, Numbers dy
WHERE
(
yr.n
BETWEEN (SELECT MIN(DatePart("yyyy", DateRanges.StartDate)) FROM DateRanges)
AND (SELECT MAX(DatePart("yyyy", DateRanges.EndDate)) FROM DateRanges)
)
AND (dy.n < 367) AND IsValidDayOfYear(yr.n, dy.n)
For your sample data, that query returns all days in 2013.
Let's save that query as [AllDays]. Now we can use it to extract the individual days for each date range (omitting StartDate so the final counts match yours in the question)
SELECT [Date] FROM AllDays
WHERE EXISTS
(
SELECT * FROM DateRanges
WHERE AllDays.[Date] BETWEEN DateAdd("d", 1, DateRanges.StartDate) AND DateRanges.EndDate
)
That returns the individual days corresponding to each range, i.e.,
Date
----------
2013-04-14
2013-04-15
2013-04-18
2013-04-19
2013-04-20
2013-04-21
2013-04-22
2013-04-23
2013-04-24
2013-04-29
2013-04-30
2013-05-01
2013-05-02
2013-05-03
2013-05-06
2013-05-07
2013-05-08
2013-05-09
2013-05-10
We can save that query as [RangeDays] and then use it to calculate our counts by month...
SELECT DatePart("m", [Date]) AS [Month], COUNT(*) AS NumOfDays
FROM RangeDays
GROUP BY DatePart("m", [Date])
...returning
Month NumOfDays
----- ---------
4 11
5 8