How to calculate an Average Value in SSRS Chart - sql

I am building a report in Report Builder for SSRS. My Data looks like:
My Column Chart is grouped by Organization, with a series group of Category and each of the 6 categories will apply to each Organization.
I'd like to add an additional Line Series to show an overall average of all categories for each Organization.
Can anyone suggest the way to achieve this? Do I need a new calculated field in SSRS, should I enhance my SQL query to get the calculation done there?
My SQL Query is:
select OrganizationUnitID,Category,AVG(NumericValue) as average
, case
when AVG(NumericValue) <= 1 then 0
when AVG(NumericValue) > 1 and AVG(NumericValue) <= 2 then 50
when AVG(NumericValue) > 2 and AVG(NumericValue) <= 3 then 75
when AVG(NumericValue) > 3 then 100 end
as percentage
from SurveyMetricView
group by OrganizationUnitID,Category
order by OrganizationUnitID
The desired result is this chart:
Thanks in advance for any advice.

This is a possible solution for the requeriment you posted.
Add textbox to your surface, just put it in any place in your report.
Set the following expression to the textbox.
=Avg(Fields!percentage.Value, "DataSetName")
Add the below expression to the series. Note in the expression that I am referencing the Textbox49 since it's the name of the textbox that I added to the report before and It contains the average of all values.
=ReportItems!Textbox49.Value
Change the chart type for the series you've added to Line Chart.
It will preview this:
You can set the Visibility property of the textbox to hidden = true
if you don't want it appears in your report.
Let me know if this was helpful

Thanks for the pointers.
In the end what I did was to create a new dataset with the following query to calculate the overall average for each Organization, essentially selecting distinct organization:
declare #st_date datetime;
declare #en_date datetime;
set #st_date = (#st_datein);
set #en_date = (#en_datein);
Select Distinct
SurveyMetricView.OrganizationUnitID,
Avg(SurveyMetricView.NumericValue) As average,
Case When Avg(SurveyMetricView.NumericValue) <= 1 Then 0
When Avg(SurveyMetricView.NumericValue) > 1 And
Avg(SurveyMetricView.NumericValue) <= 2 Then 50
When Avg(SurveyMetricView.NumericValue) > 2 And
Avg(SurveyMetricView.NumericValue) <= 3 Then 75
When Avg(SurveyMetricView.NumericValue) > 3 Then 100 End As percentage
From
SurveyMetricView
where
OrganizationUnitID in (#OrganizationUnit)
and ClosedDateTime >= #st_date
and ClosedDateTime <= #en_date
Group By
SurveyMetricView.OrganizationUnitID
Order By
SurveyMetricView.OrganizationUnitID

Related

SSRS Count Distinct Expression into a Yes or No

I'm wondering if there's a way or an expression I could use in SSRS to show a Yes or No based on a Distinct Count function?
Example of what I'm currently using - RM_Name is the group
=CountDistinct(iif(Fields!qtrtradecnt.Value >= 15, 1, Nothing), "RM_Name")
I also would like to show if the qtrtradecnt is >= 15 to show a Y or N based on the RM_Name group, and maybe countdistinct is not the correct function to use...I've messed with this for days.
Thank you!
One way to do this is to the calculation in your your dataset.. with a case expression..
select
...
,case when your_table.qtrtradecnt >= 15 then 1 else 0 end as rm_count
from your_table
Then in your report just do a
=iif(sum(Fields!rm_count.value) >15 then 'Y','N')

Return data of one Tablix (tablix 1) based on values of another Tabllx (tablix 2)

Good day, I have searched everywhere and seems like the lookup function might be the solution but I need some advise. I have a report with more than one dataset linked to it. Tablix 1 returns a count based on a name field and groups(counts) it per date on specified date range. Tablix 2 returns details on tablix 1's count with more fields including the date per row.
I need to add a "click_link" on Tablix 1 so that when you click on any of the counted values it must return the detailed data from tablix 2 but only if the date matches.
Image of Tablix 1:
Image of Tablix 2:
Image of Tablix 1's data returned without where clause
This is the query for dataset 1(Tablix 1)
DECLARE #Actual int;
DECLARE #Date varchar;
SELECT Actual.Actual,Actual.DateActual,Original.Original,Original.DateOriginal FROM
(
Select count (payhist.AC_CODEID) as Actual,PAYHIST.PH_DATE as DateActual from PAYHIST
join Paymonth on PAYHIST.PH_DATE >= Paymonth.ph_datesd and PAYHIST.PH_DATE <= Paymonth.ph_dateed
Join EMPLOYEE E on PAYHIST.MST_SQ = e.MST_SQ
Join Worklocation wl on e.wl_codeid = wl.wl_codeid
Join Paymonth pm on PAYHIST.PH_DATE >= pm.ph_datesd and PAYHIST.ph_date <= pm.ph_dateed
where Paymonth.CurrentPD = 1
and PH_EXCEPTION = 1
and e.EMP_DISCHARGE is null
and e.EMP_CONTRACTOR = 0
and wl.WL_CODEID = 1
GROUP BY PAYHIST.PH_DATE
) AS Actual
FULL JOIN
(
Select count (PAYHISTTEMP.MST_SQ) as Original,PAYHISTTEMP.PH_DATE as DateOriginal from PAYHISTTEMP
join Paymonth on PAYHISTTEMP.PH_DATE >= Paymonth.ph_datesd and PAYHISTTEMP.PH_DATE <= Paymonth.ph_dateed
Join EMPLOYEE E on PAYHISTTEMP.MST_SQ = e.MST_SQ
Join Worklocation wl on e.wl_codeid = wl.wl_codeid
Join Paymonth pm on PAYHISTTEMP.PH_DATE >= pm.ph_datesd and PAYHISTTEMP.ph_date <= pm.ph_dateed
where Paymonth.CurrentPD = 1
and PH_EXCEPTION = 1
and e.EMP_DISCHARGE is null
and e.EMP_CONTRACTOR = 0
and wl.WL_CODEID = 1
group by PAYHISTTEMP.PH_DATE
) AS Original ON Original.DateOriginal = Actual.DateActual
where (#Actual = '-1' or #Actual = Actual.Actual)
and (#date = '-1' or #date = Original.DateOriginal)
order by DateOriginal Asc
And this is the query for dataset 2
Select e.EMP_EMPNO,e.emp_Firstname,e.emp_surname,d.DPT_NAME,a.AC_NAME,ph.PH_DATE as PAYHIST_DATE,d.DPT_RESPEMP,
ph.PH_FIRSTCLOCK,ph.PH_LASTCLOCK,WL_NAME
into EXCEPREPORT
from PAYHIST PH
Join EMPLOYEE E on ph.MST_SQ = e.MST_SQ
Join DEPARTMENT D on ph.DPT_CODEID = d.DPT_CODEID
join ATTEND A on ph.AC_CODEID = a.AC_CODEID
Join Worklocation wl on e.wl_codeid = wl.wl_codeid
Join Paymonth pm on ph.PH_DATE >= pm.ph_datesd and ph.ph_date <= pm.ph_dateed
where pm.CurrentPD = 1
and PH_EXCEPTION = 1
and e.EMP_DISCHARGE is null
and e.EMP_CONTRACTOR = 0
and e.wl_codeid = 1
select pht.EMP_EMPNO,pht.EMP_FIRSTNAME,pht.EMP_SURNAME, DPT_NAME,e.emp_firstname as RESP_FIRSTNAME,e.emp_surname as RESP_SURNAME,
AC_NAME,PAYHIST_DATE,PH_FIRSTCLOCK,PH_LASTCLOCK,WL_NAME as WORKLOCATION
from EXCEPREPORT pht
join employee e on pht.dpt_respemp = e.mst_sq
drop table EXCEPREPORT
#Harry, I am completely confused now...Should the parameters be added on the summary or details tablix? I am only interested in the details of the outstanding transactions. Which I get from the summary tablix's data set. The query returns a count of one of the columns namely(AC_CODE) as well as date and the same query (using full join) to run two select queries each to different tables does a count on a similar column and date(Results as link of picture above). The details are then returned with Tablix 2's data set which is a different query and there are no identical column names except the date which is the same on both queries with different column names. Ultimately I want to send this report out as a Excel attachment and if you click on one of the dates on summary in outstanding row it must sort of bookmark to the detail sheet but only show details for relevant date above outstanding number selected. I hope this makes sense?
Please let me know if you require any additional info?
Lets assuming you have two tablix on your report.
TablixA which has the summary
TablixB that has the detail
You would have two datasets (dataset1 for the summary and dataset2 for the detail).
You already have Dataset1 and displaying TablixA without any issues.
What you need to for the details one do is have a couple of extra parameters on your Dataset2. Lets call them #status and #date
Your code / stored procedure for Dataset2 will have at the end of your where clause the following
where....
and (#status = '-1' or #status = yourtable.column_that_holds_status)
and (#date = '1990-01-01' or #date = yourtable.column_that_holds_the_date)
This will create two parameters on your report (Status and date)
Set the default value for these parameters status '-1' and date = '1990-01-01'
Set the initial visibility of TablixB to hidden.
Now on TablixA select the text box that you want to click on (lets call this textbox_click). Right click on textbox_click then go text box properties ->Action. Select "Go to Report". Under Specify a report - select the report that you are currently designing and click Add. Now click on the parameter under Name one at a time until you have all the parameters required for this report covered. Say if you had 1 parameter for TablixA called param1.. so under Name you will have param1 and the value should be set to what the initial parameter was (click on the fx next to value and select that parameter).
Now for the Name Status - select the field (column_that_holds_status) for the field list of dataset1 and date as the field from Dataset1 (column_that_holds_the_date)
Click ok.. assuming everything has been set correctly .. you can now run the report.. and when you move your cursor over the value, it should turn into a finger telling you can click.. click and then it should reload the report.. but now show the second tablix with the correct data in it.
To stop from user clicking on 0 values.. once you have everything working.. go to the "specify a report" then click the fx and use the following
=iif(reportitem!textbox_click.value>0,"Name or your currentreport",0)
It's heaps easier to show then explain.. but hope this gets you started on where you need to get to.
Lets Assume your report is called report1
Lets also assume you have the following result set from dataset1 (ignoring the actual set that is returned)
Bulyanhulu Date value
Original 22 Jan 2018 1
Original 25 Jan 2018 4
Original 26 Jan 2018 6
Original 27 Jan 2018 1
Original 02 Feb 2018 21
Outstanding 22 Jan 2018 0
Outstanding 25 Jan 2018 0
Outstanding 27 Jan 2018 0
Outstanding 02 Feb 2018 6
Cleared 22 Jan 2018 1
Cleared 25 Jan 2018 4
Cleared 27 Jan 2018 6
Cleared 02 Feb 2018 15
The above would be easy to lay out as a matrix (Tablix1)
Now for you second dataset for the details (dataset2)
You need to make sure it is returning the Bulyanhulu column as well as the date column along with other columns that you want for the details tablix( Tablix2)
So for the second data set .. you should have something like this
Select
Bulyanhulu
,Date
,whatever other colums you want
from your_table
where
(#Bulyanhulu = '-1' or #Bulyanhulu = Bulyanhulu)
and
(#date='-1' or #date = Date)
once you have done this to your dataset2, you will see two new parameters :
#Bulyanhulu and #date.
Make them Hidden
Set the default value to -1 for both the parameters
You have two tablix, Tablix1 and Tablix2
Say if we pick on Bulyanhulu-Outstanding for date '02 Feb 2018' (which has a value of 6) on Tablix1
Right click on the text box (lets call it textbox1) and
select properties -> Action
Select Go to report
Specify report1 under "Specify a report"
Click Add to add both your parameters
on the first line for paramenter Bulyanhulu select [Bulyanhulu] for the value
on the Second line for paramenter Date select [Date] for the value
once you have done this.. click on the Fx next to Specify a report and type in the following
=iif(reportitems!textbox1.value>0,"Report1",0)
This ensures that you cannot click on any values that is 0 in tablix 1
Set your Hidden property on Tablix 2 to something like this
=iif(parameters!Bulyanhulu.value = '-1',true,false)
This ensure that on initial load, this details tablix2 is hidden.. it will show only when a value is passed to this parameter by clicking on textbox1
Good luck

Crystal Reports Formula fields SUM only positive values using WHERE

Within my crystal report details section i have several values from the field amount, i added a simple formula field to my group header to calculate the SUM({Amount}) Which works however i only want it to SUM the positive values.
There is always a negative version of the positive.
Data
10
30
60
-10
-30
-60
Current Output with SUM({Amount})
0
Desired Output
100
Something like but in crystal variant
SUM({Amount}) FROM mytable WHERE {Amount} > 0
You can use two formula to fulfill ur requrement
1.#Positive_Number
if{Table.amount} > 0 then {Table.amount} else 0
2.#Sum_of_PositiveNumber
Sum ({#positive_Number})
thanks
Ankur
Another option would be a running total that sums the {Table.amount} and evaluates on a formula. {Table.amount} > 0
reset on group if your report is grouped
What i did was create a new parameter called ABSAmount :
ABS({AMOUNT})
Then another
SUM({#ABSamount})/2
This gave me the required output.

finding range by comparing two tables

I have a table in database as "EXPERIENCE RANGE" with rows as (I can also edit this table according to my need)
0
0.5
1
2
3
5
10
20
I have total experience as integer. I need to display the range in which it lies.
Example - for experience of 8, Range will be 5 - 10
I need to write a sql query. Any ideas will be quite helpful as I am new to SQL.
I cannot hard code it..need to take values from tables only.
Assuming that you are using Oracle, the following query works fine with your existing table:
SELECT
( SELECT MAX( value ) FROM experience_range WHERE value <= :search_value ) AS range_start,
( SELECT MIN( value ) FROM experience_range WHERE value > :search_value ) AS range_end
FROM dual;
No need to hardcode the values, and no need to store the lower and upper bounds redundantly.
you can do it with CASE Expression, the syntax is:
SELECT
CASE
WHEN experience >= 0 and experience <= 4 THEN '0-4'
WHEN experience >= 5 and experience <= 10 THEN '5-10'
.....
ELSE 'No Range'
END as Range
FROM Table_Name
If you do need to store the ranges in a table, I would personally suggest altering the structure of the range table (Assuming you are able to), maybe something like:
|--------------------------------------|
|ID|DESCRIPTION|LOWER_LIMIT|UPPER_LIMIT|
|1 | 0 - 0.5 | 0 | 0.5 |
|2 | 0.5 - 1 | 0.5 | 1 |
...
Then you could get your range by running something like:
SELECT DESCRIPTION FROM [RANGES] WHERE <VALUE> >= LOWER_LIMIT AND <VALUE> < UPPER_LIMIT
EDIT - Mikhail's answer also works, defining the ranges within the query itself is also an option and probably simpler providing you don't need to get these ranges from several reports. (That would require editing every report/query individually)
EDIT 2 - I see you are not able to hardcode the ranges, in which case the above would be best. Can I ask why you are unable to hardcode them?

Can a SQL query be run several times on different subsets of data?

I have a table that is just random values.
I have a query that looks something like this:
SELECT COUNT(DISTINCT(Value))
FROM RandomValueTable
WHERE
Value > #lowerRange
AND
Value < #upperRange
There will be a series of ranges I need to run this for (0-20, 21-45, 46-100 etc). Before running this query, I'll know what the ranges are. Do I need to run this query several times just filling in the range variables, or is there some way I can specify all the different ranges in one query?
You can specify them in one query using group by:
select (case when value between 0 and 20 then '0-20'
when value between 21 and 45 then '21-45'
when value between 46 and 100 then '46-100'
else 'other'
end) as range,
count(*)
from RandomValueTable
group by (case when value between 0 and 20 then '0-20'
when value between 21 and 45 then '21-45'
when value between 46 and 100 then '46-100'
else 'other'
end);