Performing IIF on a Double value in SSRS - reporting-services

I currently have a column in my report that is calculating an Average:
=FORMAT(Avg(Fields!intGradeTransposeValue.Value),"#.#")
I am currently trying to use the result of that calculation to then perform an IIF statement, but I am getting an error:
The Value expression for the textrun 'Textbox20.Paragraphs[0].TextRuns[0]' contains an error: [BC30311] Value of Type 'Microsoft.ReportingServices.ReportProcessing.ReportObjectModel.ReportItem' cannot be converted to 'Double'
My expressions is:
=CDbl(IIF(ReportItems!Textbox6 <= 1.4, "A*",
IIF(ReportItems!Textbox6 <= 2.4 AND >= 1.5, "A",
IIF(ReportItems!Textbox6 <= 3.4 AND >= 2.5, "B",
IIF(ReportItems!Textbox6 <= 4.4 AND >= 3.5, "C",
IIF(ReportItems!Textbox6 <= 5.4 AND >= 4.5, "D"
IIF(ReportItems!Textbox6 <= 6.4 AND >= 5.5, "E"
IIF(ReportItems!Textbox6 <= 7.4 AND >= 6.5, "U", "Error"))))))))
How can I do the calculation I need?
ADDITIONAL
I have added below where the error is coming - this is confusing me as it seems to be accepting the first double of 1.4. I am using the suggested answer below, but this is also not working.

Based on the error you are receiving, the issue is that you are attempting to convert the ReportItems!Textbox6 itself to a double, not the value within it. In order to reference the value of the Textbox, you'll need to reference it as ReportItems!Textbox6.Value. So I believe the answer you'll need will combine arahman's answer with this change:
=IIF(CDbl(ReportItems!Textbox6.Value) <= 1.4, "A*",
IIF(CDbl(ReportItems!Textbox6.Value) <= 2.4 AND >= 1.5, "A",
IIF(CDbl(ReportItems!Textbox6.Value) <= 3.4 AND >= 2.5, "B",
IIF(CDbl(ReportItems!Textbox6.Value) <= 4.4 AND >= 3.5, "C",
IIF(CDbl(ReportItems!Textbox6.Value) <= 5.4 AND >= 4.5, "D"
IIF(CDbl(ReportItems!Textbox6.Value) <= 6.4 AND >= 5.5, "E"
IIF(CDbl(ReportItems!Textbox6.Value) <= 7.4 AND >= 6.5, "U", "Error")))))))
Source
Based on the edit to the original post, I missed the other issue with the expression. You can't compare the values like that. You'll need to add additional references to the Textbox value after the AND.
=IIF(CDbl(ReportItems!Textbox6.Value) <= 1.4, "A*",
IIF(CDbl(ReportItems!Textbox6.Value) <= 2.4 AND CDbl(ReportItems!Textbox6.Value) >= 1.5, "A",
IIF(CDbl(ReportItems!Textbox6.Value) <= 3.4 AND CDbl(ReportItems!Textbox6.Value) >= 2.5, "B",
IIF(CDbl(ReportItems!Textbox6.Value) <= 4.4 AND CDbl(ReportItems!Textbox6.Value) >= 3.5, "C",
IIF(CDbl(ReportItems!Textbox6.Value) <= 5.4 AND CDbl(ReportItems!Textbox6.Value) >= 4.5, "D",
IIF(CDbl(ReportItems!Textbox6.Value) <= 6.4 AND CDbl(ReportItems!Textbox6.Value) >= 5.5, "E",
IIF(CDbl(ReportItems!Textbox6.Value) <= 7.4 AND CDbl(ReportItems!Textbox6.Value) >= 6.5, "U", "Error")))))))

I am pretty sure you are saying cast the output which would be string value of A* or B etc as double. Which gives the error cannot cast to double.
You would probably want to wrap the reportItems sections in the CDbl() instead to cast that number and then compare it against your static double values.
You would only cast the field this way if it really needed to be changed to a double for comparison.
=IIF(CDbl(ReportItems!Textbox6) <= 1.4, "A*",
IIF(CDbl(ReportItems!Textbox6) <= 2.4 AND >= 1.5, "A",
IIF(CDbl(ReportItems!Textbox6) <= 3.4 AND >= 2.5, "B",
IIF(CDbl(ReportItems!Textbox6) <= 4.4 AND >= 3.5, "C",
IIF(CDbl(ReportItems!Textbox6) <= 5.4 AND >= 4.5, "D"
IIF(CDbl(ReportItems!Textbox6) <= 6.4 AND >= 5.5, "E"
IIF(CDbl(ReportItems!Textbox6) <= 7.4 AND >= 6.5, "U", "Error")))))))

Related

color code text box in SSRS report based on date range

i'm trying to color code a text box in Report based on date range. when i run below expression i'm getting error
The Background Color expression for the text box ‘NSIXMONTH’ contains
an error: [BC30198] ')' expected.
"
Can anyone please help.
=IIF( IsNothing(Fields!NSIXMONTH.Value), "Transparent"
,IIF (Fields!NSIXMONTH.Value <= DATEADD("D", -( DAY( Fields!NSIXMONTH.Value), Fields!NSIXMONTH.Value), "RED"
, IIF ( TODAY() > = DATEADD("MM", DATEDIFF ( "MM", 0 , Fields!NSIXMONTH.Value),0)
AND
TODAY() < = DATEADD ( "D", -1, DATEADD ( "MM", DATEDIFF("MM", 0, Fields!NSIXMONTH.Value) +1 ,0)),"YELLOW,"Transparent" ))))
There's an right parenthesis in the first DATEADD's second argument -( DAY( Fields!NSIXMONTH.Value)
It's easier to find issues like this if you use line breaks and tabs to format the expression
=IIF( IsNothing(Fields!NSIXMONTH.Value),
"Transparent" ,
IIF (Fields!NSIXMONTH.Value <= DATEADD("D", - DAY( Fields!NSIXMONTH.Value), Fields!NSIXMONTH.Value),
"RED" ,
IIF ( TODAY() > = DATEADD("MM", DATEDIFF ( "MM", 0 , Fields!NSIXMONTH.Value),0) AND TODAY() < = DATEADD ( "D", -1, DATEADD ( "MM", DATEDIFF("MM", 0, Fields!NSIXMONTH.Value) +1 ,0)),
"YELLOW,
"Transparent"
)
)
)
But with multiple conditions, it's even easier to use the SWITCH statement. The SWITCH evaluates the first expression and if true returns the 2nd argument. If False, it goes the Argument 3 and so on.
=SWITCH( IsNothing(Fields!NSIXMONTH.Value), "Transparent" ,
Fields!NSIXMONTH.Value <= DATEADD("D", 0 - DAY(Fields!NSIXMONTH.Value), Fields!NSIXMONTH.Value), "RED" ,
TODAY() > = DATEADD("MM", DATEDIFF ( "MM", 0 , Fields!NSIXMONTH.Value),0) AND TODAY() < = DATEADD ( "D", -1, DATEADD ( "MM", DATEDIFF("MM", 0, Fields!NSIXMONTH.Value) +1 ,0)), "YELLOW,
1 = 1, "Transparent"
)

How to do colour formatting in drilldown pivot report

I have made a Drill down report in SSRS 2008 with one parent group and 4 child group each group field aggregates value under a pivot column.I have to do conditional formatting to change the background color of the pivot field if the particular aggregate value exceeds the input value on each drilldown field.
I have tried multiple expression With 'IIF' and 'SWITCH' condition to change the background color in pivot field in each drill down field.
=switch(
Fields!CIRCLE.Value,"DataSet1" AND (fields!TOTAL.Value>30000,"DataSet1"),"Red",
(Fields!ZONE.Value,"DataSet1" AND (fields!TOTAL.Value>100,"DataSet1"),"Red",
(Fields!CLUSTER.Value,"DataSet1" AND (fields!TOTAL.Value>5000,"DataSet1"),"Red",
(Fields!NODE.Value,"DataSet1" AND (fields!TOTAL.Value>3000,"DataSet1"),"Red","White"
))))
I want the Pivot field Hour with sum as aggregates to turn red on circle level zone level,cluster level and node level like example if the Sum field under pivot column is 700 in 3rd hour and it exceeds 300 then the value at 3rd hour should turn red on circle level.
Try this method:
=switch( Fields!CIRCLE.Value > 30000 AND Fields!TOTAL.Value >30000,"Red",
Fields!ZONE.Value> 100 AND Fields!TOTAL.Value > 100,"Red",
Fields!CLUSTER.Value > 5000 AND Fields!TOTAL.Value > 5000,"Red",
Fields!NODE.Value > 3000 AND Fields!TOTAL.Value > 3000 ,"Red")
#Aditi Singh we are on the correct track, have a look at images below, let me know your thoughts:
#SuperSimmer44 Below is the link image for the desried Output-
Drilldown Report sampleScenario: Circle>4000(Red), Zone>3000(Red), Cluster>500(Red)
Try this method (you will need to extend to hour value 10+):
=switch(Fields!HOUR1.Value = "1" and Fields!TOTAL.Value >= "100", "RED",
Fields!HOUR1.Value = "2" and Fields!TOTAL.Value >= "200", "RED",
Fields!HOUR1.Value = "3" and Fields!TOTAL.Value >= "300", "RED",
Fields!HOUR1.Value = "4" and Fields!TOTAL.Value >= "400", "RED",
Fields!HOUR1.Value = "5" and Fields!TOTAL.Value >= "500", "RED",
Fields!HOUR1.Value = "6" and Fields!TOTAL.Value >= "600", "RED",
Fields!HOUR1.Value = "7" and Fields!TOTAL.Value >= "700", "RED",
Fields!HOUR1.Value = "8" and Fields!TOTAL.Value >= "800", "RED",
Fields!HOUR1.Value = "9" and Fields!TOTAL.Value >= "900", "RED",
)

Multiple nested iif statement in Access

I am trying to calculate the number of vacation week an employee is entitled to using their years of service, with these categories:
0-4 years = 2 weeks
5-14 years = 3 weeks
15-24 years = 4 weeks
25 and up = 5 weeks
I found some examples and tried doing a nested iif statement but keep getting an error message. Can someone tell me what I am doing wrong?
VacationWeeks: IIf([YearsInService]<=4, "2",
IIf([YearsInService]is between 5 and 14, "3",
IIf([YearsInService]is between 15 and 24, "4",
IIf([YearsInService]>=25, "5", ”0”))))
You are likely receiving error messages because of two issues with your code:
A BETWEEN statement has the syntax:
expr [Not] Between value1 And value2
You should not include the word is:
IIf([YearsInService] is between 5 and 14,
^-------------------- this shouldn't be here
Your final else argument encloses the string in 'smart quotes' or Unicode character 0x201C:
IIf
(
[YearsInService] >= 25,
"5",
”0” <--- here
)
As opposed to the standard double-quote, which is Unicode/ASCII character 0x0022:
IIf
(
[YearsInService]>=25,
"5",
"0"
)
Correcting these two issues would yield an IIF statement such as:
IIf
(
[YearsInService] <= 4,
"2",
IIf
(
[YearsInService] between 5 and 14,
"3",
IIf
(
[YearsInService] between 15 and 24,
"4",
IIf
(
[YearsInService] >= 25,
"5",
"0"
)
)
)
)
However, you may find the use of a SWITCH statement more readable:
Switch
(
[YearsInService] <= 4, "2",
[YearsInService] <= 14, "3",
[YearsInService] <= 24, "4",
[YearsInService] > 24, "5",
True, "0"
)
The last test expression provides a catch-all default to account for nulls and still return a string value - I'll let you decide whether you wish to include or omit this, depending on the requirements of your application.

How can I optimize the following MySQL query to achieve concurrent calls per seconds?

The following query read data from DB1.Data table, the query working correctly but is very slow.
This query result is concurrent calls from CDR information.
Mysql query
select sql_calc_found_rows H,M,S,(TCNT+ADCNT) as CNT from
(
select H,M,S,sum(CNT) as TCNT,
(
select
count(id) as CNT
from DB1.Data force index (datetimeOrgination) where 1=1 and
(datetimeOrgination<UNIX_TIMESTAMP(concat('2018-02-09',' ',T1.H,':',T1.M,':',T1.S)) and (datetimeOrgination+callDuration)>UNIX_TIMESTAMP(concat('2018-02-09',' ',T1.H,':',T1.M,':',T1.S)))
and (DB1.Data.datetimeOrgination between UNIX_TIMESTAMP('2018-02-09 00:00:00') and UNIX_TIMESTAMP('2018-02-09 23:59:59'))
) as ADCNT
from
(
(select
hour(from_unixtime(datetimeOrgination)) as H,
minute(from_unixtime(datetimeOrgination)) as M,
second(from_unixtime(datetimeOrgination)) as S,
count(id) as CNT
from DB1.Data where 1=1 and (DB1.Data.datetimeOrgination between UNIX_TIMESTAMP('2018-02-09 00:00:00') and UNIX_TIMESTAMP('2018-02-09 23:59:59'))
group by hour(from_unixtime(datetimeOrgination)),minute(from_unixtime(datetimeOrgination)),second(from_unixtime(datetimeOrgination)))
Union all
(select
hour(from_unixtime(datetimeOrgination+callDuration)) as H,
minute(from_unixtime(datetimeOrgination+callDuration)) as M,
second(from_unixtime(datetimeOrgination+callDuration)) as S,
count(id) as CNT
from DB1.Data force index (datetimeOrgination) where 1=1 and
(second(from_unixtime(datetimeOrgination+callDuration))>second(from_unixtime(datetimeOrgination))) and (DB1.Data.datetimeOrgination between UNIX_TIMESTAMP('2018-02-09 00:00:00') and UNIX_TIMESTAMP('2018-02-09 23:59:59'))
group by hour(from_unixtime(datetimeOrgination+callDuration)),minute(from_unixtime(datetimeOrgination+callDuration)),second(from_unixtime(datetimeOrgination+callDuration)))
) as T1 group by H,M,S
) as T2;
Here's the explain output
This is the query output in JSON format:
{
"meta": {
"count": 18,
"totalCount": 18
},
"calls": [{
"H": 10,
"M": 30,
"S": 44,
"CNT": 1
}, {
"H": 11,
"M": 27,
"S": 1,
"CNT": 1
}, {
"H": 11,
"M": 28,
"S": 44,
"CNT": 1
}, {
"H": 12,
"M": 23,
"S": 52,
"CNT": 1
}, {
"H": 12,
"M": 29,
"S": 27,
"CNT": 1
}, {
"H": 12,
"M": 30,
"S": 38,
"CNT": 1
}, {
"H": 14,
"M": 26,
"S": 17,
"CNT": 1
}, {
"H": 14,
"M": 26,
"S": 44,
"CNT": 1
}, {
"H": 14,
"M": 26,
"S": 51,
"CNT": 1
}, {
"H": 14,
"M": 27,
"S": 2,
"CNT": 1
}, {
"H": 14,
"M": 27,
"S": 8,
"CNT": 1
}, {
"H": 14,
"M": 40,
"S": 27,
"CNT": 1
}, {
"H": 14,
"M": 40,
"S": 57,
"CNT": 1
}, {
"H": 14,
"M": 40,
"S": 58,
"CNT": 1
}, {
"H": 15,
"M": 8,
"S": 4,
"CNT": 1
}, {
"H": 15,
"M": 8,
"S": 31,
"CNT": 1
}, {
"H": 15,
"M": 56,
"S": 38,
"CNT": 1
}, {
"H": 16,
"M": 27,
"S": 30,
"CNT": 1
}]
}
The first record in result
"H": 10,
"M": 30,
"S": 44,
"CNT": 1
shows we have 1 concurrent call at 10:30:44
More details
For calculate the concurrent calls per seconds, we should count 3 type of calls per second.
For example, if we want to calculate concurrent calls for 10:51:20 we need to count all of the following:
Step 1-Count all calls started at 10:51:20
Step 2-Count all calls ended at 10:51:20, but not started in the same second(20).
Step 3-Count all calls started before 10:51:20 and ended after 10:51:20.
Step 4- Finally needs to sum all of them to calculate the concurrent calls.
This query is for Step 1
(select
hour(from_unixtime(datetimeOrgination)) as H,
minute(from_unixtime(datetimeOrgination)) as M,
second(from_unixtime(datetimeOrgination)) as S,
count(id) as CNT
from DB1.Data where 1=1 and (DB1.Data.datetimeOrgination between UNIX_TIMESTAMP('2018-02-09 00:00:00') and UNIX_TIMESTAMP('2018-02-09 23:59:59'))
group by hour(from_unixtime(datetimeOrgination)),minute(from_unixtime(datetimeOrgination)),second(from_unixtime(datetimeOrgination)))
This query is for Step 2
(select
hour(from_unixtime(datetimeOrgination+callDuration)) as H,
minute(from_unixtime(datetimeOrgination+callDuration)) as M,
second(from_unixtime(datetimeOrgination+callDuration)) as S,
count(id) as CNT
from DB1.Data force index (datetimeOrgination) where 1=1 and
(second(from_unixtime(datetimeOrgination+callDuration))>second(from_unixtime(datetimeOrgination))) and (DB1.Data.datetimeOrgination between UNIX_TIMESTAMP('2018-02-09 00:00:00') and UNIX_TIMESTAMP('2018-02-09 23:59:59'))
group by hour(from_unixtime(datetimeOrgination+callDuration)),minute(from_unixtime(datetimeOrgination+callDuration)),second(from_unixtime(datetimeOrgination+callDuration)))
This query is for Step 3 from the union result of 2 previous query
(
select
count(id) as CNT
from DB1.Data force index (datetimeOrgination) where 1=1 and
(datetimeOrgination<UNIX_TIMESTAMP(concat('2018-02-09',' ',T1.H,':',T1.M,':',T1.S)) and (datetimeOrgination+callDuration)>UNIX_TIMESTAMP(concat('2018-02-09',' ',T1.H,':',T1.M,':',T1.S)))
and (DB1.Data.datetimeOrgination between UNIX_TIMESTAMP('2018-02-09 00:00:00') and UNIX_TIMESTAMP('2018-02-09 23:59:59'))
) as ADCNT
This query gathers all of them and returns the final result.
select sql_calc_found_rows H,M,S,(TCNT+ADCNT) as CNT from
(
As I mentioned before, that query working but very slow and complex, I know needs optimization and simplification.
Field types
`datetimeOrgination` BIGINT(20) NOT NULL DEFAULT
`callDuration` BIGINT(20) NOT NULL DEFAULT '0',
and indexs
INDEX `datetimeOrgination` (`datetimeOrgination`),
INDEX `callDuration` (`callDuration`),
Caveat: Some of my suggestions are for clarity or simplification, not necessarily for speed.
Potential bug: and (second(from_unixtime(datetimeOrgination+callDuration)) > second(from_unixtime(datetimeOrgination))) does not make much sense. It will catch a 2-second call that started at 11:22:00, but not one that started at 11:21:59. Is that really what you wanted? In any case, please explain what the query is trying to do.
Don't work with H,M,S, work with just seconds -- either by extracting the hh:mm:ss string from the date, or by getting the time of day in seconds. Convert to H,M,S as the last step, not the first.
Don't FORCE INDEX -- it may help today, but hurt tomorrow.
Change and (DB1.Data.datetimeOrgination between UNIX_TIMESTAMP('2018-02-09 00:00:00') AND UNIX_TIMESTAMP('2018-02-09 23:59:59')) to
AND DB1.Data.datetimeOrgination >= '2018-02-00'
AND DB1.Data.datetimeOrgination < '2018-02-00' + INTERVAL 1 DAY
(Again, that is for clarity, not speed.)
Use COUNT(*) instead of COUNT(id)
I'm doing a lot of guessing; help us out by providing SHOW CREATE TABLE. It smells like you are using the wrong datatype for datetimeOrgination.
After converting to seconds (from H,M,S), this
datetimeOrgination < UNIX_TIMESTAMP(concat('2018-02-09',' ',',T1.H,':',T1.M,':',T1.S)
becomes something like
datetimeOrgination < '2018-02-09' + INTERVAL secs SECOND
Even better would be to extract the datetime from the subquery and move to something like
datetimeOrgination < datetime_from_subquery
This may give a better chance of using the index.
Cleanup the code and explain the goal; I'll try to come up with some more speedups.
(Since the definition of the problem is moving, I am starting a new Answer.)
The number of calls (of all types) at a specific point in time is simply:
SELECT COUNT(*) FROM tbl
WHERE call_start <= '2018-02-14 15:11:35'
WHERE call_start + duration >= '2018-02-14 15:11:35';
But, I will quibble that the answer is "high" because it does not take into account what part of the given second the call started or ended. So, I think this is closer to correct:
SELECT COUNT(*) FROM tbl
WHERE call_start < '2018-02-14 15:11:35'
WHERE call_start + duration >= '2018-02-14 15:11:35';
This should come as close as possible to saying how many concurrent calls happened at exactly '2018-02-14 15:11:35.000000'; it is an approximation of the number for '2018-02-14 15:11:35.5'.
By changing COUNT(*) to SUM(...) (as already discussed), you can get the count for a given type of call.
Then you add GROUP BY using datetime or timestamp arithmetic to finish out the task.
One day
To catch all calls that started during a single day:
WHERE call_start >= '2018-02-09'
AND call_start < '2018-02-09' + INTERVAL 1 DAY
Problem Definition is wrong
For calculate the concurrent calls per seconds, we should count 3 type
of calls per second...
I contend that that is mathematically wrong.
"Concurrent calls" is at an instant, not across a whole second (or hour or day). It means "how many phone connections are in use at that instant.
Let me change the statement of the problem to "concurrent calls per hour". Does that make sense? You can ask about "calls per hour", which could be interpreted as "calls initiated per hour" and be computed via datetimeOrgination and a GROUP BY.
Suppose I calls at the start of each minute, and each lasted 59 seconds. A single phone line could handle that. I suggest that is "1 concurrent call".
In contrast, what if I had 60 people all starting their 59-second calls at noon. That would take 60 phone lines. That would be 60 concurrent calls during the busy time of the day.
The metric you have involves a datetimeOrgination that is truncated (or rounded?) to a 1-second boundary.
Not let me modify the example to better explain why your 3 steps are wrong. I want to group by hour, and I am willing to measure the number of calls at the top of the hour. In particular, let's look at the 10 o'clock hour.
09:55 - 10:05 -- a 10-minute call that is counted, by your algorithm in each of 09 and 10 hours.
10:20 - 10:30 -- a 10-minute call that is counted, by your algorithm in only the 10 hour.
Why should a 10-minute call be counted as belong to two hours? This inflates the "concurrency" count.
09:05 - 10:55 -- a 110-minute call that is also counted in each of 09 and 10 hours.
09:30 - 11:30 -- a 110-minute call that is also counted 3 hours. Again, over-counting.
So, I contend that the only reasonable computation is to
Step 1-Count all calls started at 10:51:20 -- counted as happening at the :20 instant.
Step 2-Count all calls ended at before 10:51:20, but not started in the same second(20). -- not counted for :20.
Step 3-Count all calls started before 10:51:20 and ended after 10:51:20. -- counted for the :20 instant.
My suggested solution achieves that modification, and is both simpler and mathematically 'correct'.

Querying Date in MySQL for month or a week from ActiveRecord in Rails 3

So, I have a table that has two dates in it, a start and and an end date. I need to be able to query to find out all of the records that are within a certain week. So, for instance:
start: "2012-03-12 14:00:00", end: "2012-03-12 21:00:00"
start: "2012-03-13 14:00:00", end: "2012-03-13 21:00:00"
start: "2012-03-14 13:00:00", end: "2012-03-14 20:00:00"
start: "2012-03-15 15:00:00", end: "2012-03-15 22:00:00"
start: "2012-03-16 14:00:00", end: "2012-03-16 21:00:00"
I want to return all of these records by querying (somehow) "What records fall in the week of March 11 to March 17?"
I need to do this in ActiveRecord and Rails 3.2.1. Also, I would prefer if I could do this from another model. Like this dates belong to another model, let's call it ModelA.
ModelA.dates.where(What ever I need to do)
Something like that?
ModelA.dates.where('start >= ? OR end <= ?', week_start, week_end)
Or:
ModelA.dates.where('start >= ? AND start <= ? AND end >= ? AND end <= ?', week_start, week_end, week_start, week_end)