SSRS 2012 Dynamic Column Number - reporting-services

I got a request from the client when using SSRS reporting Service. I am kind of new to the SSRS. hope that someone can help me out with the problem below.
I use a common example to show the problem.
In SSRS dataset1, the data is like follows
StuId StuSubject
--------------------------------
1 "Math"
1 "Geography"
2 "Science"
3 "Math"
3 "History"
3 "Music"
In the SSRS dataset2, the data is like this one
StuId StuName
------------------------
1 "Tom"
2 "Joseph"
3 "Linda"
In the SSRS DataSet3 , it would be like
StuId StuInt
--------------------------
1 "Swim"
2 "Chess"
2 "Swim"
2 "Running"
3 "Game"
What i want in the SSRS report would be like this one
StuId StuName StuSubject StuSubject StuSubject StuInt StuInt StuInt
1 "Tom" "Math" "Geography" NULL "Swim" NULL NULL
2 "Joseph" "Science" NULL NULL "Chess" "Swim" "Running"
3 "Linda" "Math" "History" "Music" "Game" NULL NULL
The tricky part is that I don't know what is the maximum number of StuSubject for all these students, or more precisely, I don't like to set the limit of the 'StuSubject' columns because there could be hundred columns in the real case. I have thought of LookupSet function, but seems using LookupSet, you can only join multiple StuSubjects values with "," in one cell.
Any advice / suggestion would be much appreciated and thanks in advance
Edit : I could use Matrix control for one "join" situation, but is this possible to "join" multiple datasets into one finale one ?

The solution for you is to use Matrix report item - it allows to perform data grouping by rows and columns. Your data, returned from DB, should be aggregate of those two datasets that you have - it should be set of rows in format (StuId, StuName, StuSubject).
You can then add row grouping by StuId (and child row grouping by StuName, but this is not necessary), and add column grouping by StuSubject. Details cell will simply output StuSubject.
Notice that although Lookup* functions allow you to do join data while processing the report, they are run while processing report by SSRS and thus are certainly less efficient (from my experience expressions almost always have really bad impact on report performance). Also, doing join whikle processing report is not a canonical way to develop the report, and not the best way to use SSRS engine, which works good when you need simple grouping or do not need grouping at all. The best approach is to generate SQL result as much close to what you want to display, as it is possible, taking into account context of report and common sense of course.

Follow the below steps:
Use your DataSet1 in your matrix as suggested approach from LINK.
Your query would be similar to below:
Select StuId,StuSubject
'StuSubject' + Cast(row_number() over (partition by id order by score) as INT) StuSubjectVal
from table
You should get the result like below (after using matrix).
StuId StuSubject1 StuSubject2 StuSubject3......
Add a column to your matrix, and use the Lookup from DataSet1 to DataSet2.
=Lookup(Fields!StuId.Value, Fields!StuId.Value, Fields!StuName.Value, "DataSet2")
Have not tested it, but it should work.

Related

How to Combine Fields from Two Datasets SSRS?

I am working on a report to show the total number of hours an employee spent working. Our company tracks labor hours by Service Request and Work Order so I need to bring totals for each into the report.
I created two datasets- one for Work Orders and one for Service Requests. Ideally, I would like to combine the total number of Work Order hours with the total number of Service Request hours and present that number listed by employeeID since both datasets have the employeeID field.
I thought it would be as simple as:
=(SUM(Fields!TOTALHOURS_WO.Value, "DataSet1") + SUM(Fields!TOTALHOURS_SR.Value, "DataSet2"))
I don't get an error, however, I am getting a number which repeats for each employee so I know I'm doing something wrong.
Any help is greatly appreciated.
Mal,
As #StevenWhite mentioned, LOOKUP is probably the function you are looking for.
Here is an example for you. For the example datasets:
EmployeeID | TOTALHOURS_WO
-----------------------------------
123 | 12
456 | 3
EmployeeNum| TOTALHOURS_SR
-----------------------------------
123 | 2
456 | 5
You will note that each table in a SSRS report needs a DataSet assigned to it. I will assume your table is using our first DataSet, which we will name "DataSet1". The second dataset above will be "DataSet2".
For your total hours you will use an expression. It should look something like this:
=TOTALHOURS_WO + LOOKUP(Fields!EmployeeID.Value, Fields!EmployeeNum.Value, Fields!TOTALHOURS_SR.Value, "DataSet2")
So you will be adding the TOTALHOURS_WO from your local dataset to the result from the LOOKUP function. What lookup is doing is taking the first field from your local dataset, finding a match in the dataset provided to the function (as a string), and returning the field from the row it matched to. The last parameter is the dataset to search.
Just in case you get an error... it's always a good idea to cast data to the type you want to work with in case it comes in wrong. So...
=CINT(TOTALHOURS_WO) + CINT(LOOKUP(Fields!EmployeeID.Value, Fields!EmployeeNum.Value, Fields!TOTALHOURS_SR.Value, "DataSet2"))
This assumes you have a one to one match on employee ID. If you have to SUM both fields you can try this:
=SUM(CINT(TOTALHOURS_WO)) + SUM(LOOKUPSET(Fields!EmployeeID.Value, Fields!EmployeeNum.Value, CINT(Fields!TOTALHOURS_SR.Value), "DataSet2"))
SUM for TOTALHOURS_WO will give you the SUM in your current table group (so make sure you are grouping by staff ID in the table). It will then add it to the SUM of LOOKUPSET. LOOKUPSET works the same as lookup but returns an array of matches instead of the first.
Hope this helps.

Lookup on 2 datasets in SSRS

I am having a problem using Lookups in a ssrs report. The report takes in 3 datasets that I do not have the opportunity to edit or merge (three different cubes)
It is a sales report that should be grouped by Sales Manager and show the potential for sales and a "discounted potential" of sales. The problem I face is that I have to loop my table on DataSet1 since it is the only on that holds Sales Mangers.
Using LookupSet and LookupSum it is easy enough to get the potential from DataSet2. Something like:
=Code.LookupSum(LookupSet(Fields!Country.Value, Fields!Country.Value, Fields!Potential.Value, "DataSet2"))
The problem arises when I try to calculate the Discounted Potential form DataSet3
Namely because I need to perform the lookup based on a value that is not in DataSet1! Is this somehow possible?
The datasets and the desired report look like this
You should be able to change the dataset of the tablix to DataSet2 to get the desired results. Dataset2 is the only dataset that directly relates to both of the other datasets, and since nested Lookups are not allowed, and also since you cannot modify your datasets, this is necessary for this situation.
I'm not sure exactly what calculation you are using to end up with your "Discount" column, I couldn't figure out any formula that worked with all of your sample data shown. For my test I just took the Sum to make sure it was working, but you should be able to modify that to fit your needs.
I set up a tablix like so:
+---------------------------------------------------+
| Manager | Country | Potential | Discount |
| <Expr1> | [Country] | [Sum(Potential)] | <Expr2> |
+---------------------------------------------------+
With 2 row groups, the first grouping on Expr1, and the child group grouping on Country, where Expr1 is =Lookup(Fields!Country.Value, Fields!Country.Value, Fields!Manager.Value, "DataSet1") and Expr2 is =Sum(Code.SumLookup(LookupSet(Fields!Customer.Value, Fields!Customer.Value, Fields!Discount.Value, "DataSet3"))). I sorted the parent row group by Country to keep the sorting the same as you had it in your screenshot. Again though, you would likely have to modify Expr2 to fit your needs. If the discount is a percentage for that particular customer, then the following code should work for that, but the results don't match your screenshot so I'm not sure if this is what you are looking for:
=Sum(Fields!Potential.Value - (Fields!Potential.Value * Code.SumLookup(LookupSet(Fields!Customer.Value, Fields!Customer.Value, Fields!Discount.Value, "DataSet3")) / 100))
Results from using the modified Expr2 if Discount is a percentage:

RowNumber for group in SSRS 2005

I have a table in a SSRS report that is displaying only a group, not the table details. I want to find out the row number for the items that are being displayed so that I can use color banding. I tried using "Rowcount(Nothing)", but instead I get the row number of the detail table.
My underlying data is something like
ROwId Team Fan
1 Yankees John
2 Yankees Russ
3 Red Socks Mark
4 Red Socks Mary
...
8 Orioles Elliot
...
29 Dodgers Jim
...
43 Giants Harry
My table showing only the groups looks like this:
ROwId Team
2 Yankees
3 Red Socks
8 Orioles
29 Dodgers
43 Giants
I want it to look like
ROwId Team
1 Yankees
2 Red Socks
3 Orioles
4 Dodgers
5 Giants
You can do this with a RunningValue expression, something like:
=RunningValue(Fields!Team.Value, CountDistinct, "DataSet1")
DataSet1 being the name of the underlying dataset.
Consider the data:
Creating a simple report and comparing the RowNumber and RunningValue approaches shows that RunningValue gives your required results:
You can easily achieve this with a little bit of vbcode. Go to Report - Properties - code and type something like:
Dim rownumber = 0
Function writeRow()
rownumber = rownumber + 1
return rownumber
End Function
Then on your cell, call this function by using =Code.writeRow()
As soon as you start using groups inside the tables, the RowNumber and RunningGroup functions start getting some weird behaviours, thus it's easier to just write a bit of code to do what you want.
I am not convinced all suggestions above provide are a one for all solution. My scenario is I have a grouping that has has multiple columns. I could not use the agreed solution RunningValue because I don't have a single column to use in the function unless I combine (say a computed column) them all to make single unique column.
I could not use the VBA code function as is for the same reason and I had to use the same value across multiple columns and multiple properties for that matter unless I use some other kind of smarts where if I knew the number of uses (say N columns * M properties) then I could only update the RowNumber on every NxM calls however, I could not see any count columns function so if I added a column I would also need to increase my N constant. I also did not want to add a new column as also suggested to my grouping as I could not figure out how to hide it and I could not write a vba system where I could call function A that returns nothing but updates the value (i.e. called only once per group row) then call another function GetRowNumber which simply returns the rownumber variable because the colouring was done before the call so I always had one column out of sync to the rest.
My only other 2 solutions I could think of is put the combined column as mentioned earlier in the query itself or use DENSE_RANK and sort on all group columns, i.e.
DENSE_RANK() OVER (ORDER BY GroupCol1, GroupCol2, ...) AS RowNumber

Populating with '0' when Data in SSRS Does not exist

I'm trying to create a report in SSRS where I have a matrix, which has gender as the column headings and specifically defined agegroups as the rows. The report is sorted by date (ie, the records being displayed are filtered by the modifedAt value). My problem is that i wish for all of the age group categories to be displayed, even if the dataset does not return any data for that row.
So, for example, if i set the date to be a date where there are no db rows where there are Age5-16 children in - I still want to display the category name, but just have the cells related to that row to display '0'. Instead, the report just drops the whole row because, obviously the query returns no data.
Is the solution to have a separate dataset that brings back the entire list of categories and then somehow fit them together? I'm stuck here so any help is appreciated!
I can think of a few ways to do this:
DataSet level
Instead of just returning the relevant data in the underlying data in the DataSet, include all the categories you want to display in all cases.
e.g. For a database query it might be the difference between an inner and left join, i.e. going from something like:
select *
from AgeGroup
inner join MyData on ...
to:
select *
from AgeGroup
left join MyData on ...
So the report always has all the age groups to display. Where there are NULL values, just display 0.
I think this is the best option if you have control over the DataSet - you won't have to update your report at all, with luck the actual DataSet changes should be minimal, there is still only one DataSet call, and it's by far the simplest to maintain.
Hard code groups into the report
Here you include a table header row for each group you want to display, so these are always displayed in all cases.
Here you have some sort of conditional expression to display the values, e.g. For each group row it will be tailored to that group:
=Sum(IIf(Fields!AgeGroup.Value = "5-16", Fields!Amount.Value, Nothing)
This is not too flexible and will need updates as you change groups, and doesn't have as many options for layout. There is still only one DataSet call, so that is a plus.
Subreports
You can have a parent DataSet that displays one row for each age group, then embed a subreport in each row that displays the data you want for that row.
This allows you flexibility in layout but it will add complexity to the report(s) and will mean that you make a lot of DataSet calls that could be avoided with other options.
I know this is old, but I wanted to elaborate on Ian's section 1 above using joins at the dataset level. (His answer was super helpful to me for a report I'm working on.)
per op:
Is the solution to have a separate dataset that brings back the entire list of categories and then somehow fit them together?
That is how I've handled it successfully, but you can do so without actually creating a separate dataset by using common table expressions (or temp tables, of course).
For these example tables:
AGE_Table
ID Group Group_Desc Toys
1 A 00-10 Teddy Bear
2 B 11-20 Video Game
3 C 21-30 Sports Car
4 D 31-40 Mansion
5 E 41-50 Jewelry
People_Table (filtered for whatever date)
ID Name Age Gender Age_Group
1 Ariel 07 F A
2 Brandon 23 M C
3 Chelsea 27 F C
4 Derek 06 M A
You want to see 2 results for the 00-10 row, 2 for the 21-30 row, and then still see rows for the other age groups even if there aren't any results.
We want to create a dataset with all the different age groupings and then join on it. Behold a solution using common table expressions:
with CTE_Age AS
(SELECT Distinct Age_Group from AGE_Table)
SELECT ID, Name, Age, Gender, CTE_Age.Age_Group FROM People_Table
RIGHT JOIN CTE_Age ON
People_Table.Age_Group = CTE_Age.Age_Group
This will return:
ID Name Age Gender Age_Group
1 Ariel 7 F A
4 Derek 6 M A
NULL NULL NULL NULL B
2 Brandon 23 M C
3 Chelsea 27 F C
NULL NULL NULL NULL D
NULL NULL NULL NULL E
Once you have that in your dataset, you can change NULL values to 0 on the report builder side -- I think in 2008R2 the default is just blank.

Count a specific value from multiple columns and group by values in another column... in mysql

Hey. I have 160 columns that are filled with data when a user fills a report form out and submit it. A few of these sets of columns contain similar data, but there needs to be multiple instance of this data per record set as it may be different per instance in the report.
For example, an employee opens a case by a certain type at one point in the day, then at another point in the day they open another case of a different type. I want to create totals per user based on the values in these columns. There is one column set that I want to target right now, case type. I would like to be able to see all instances of the value "TSTO" in columns CT1, CT2, CT3... through CT20. Then have that sorted by the employee ID number, which is just one column in the table.
Any ideas? I am struggling with this one.
So far I have SELECT CT1, CT2, CT3, CT4, CT5, CT6, CT7, CT8, CT9, CT10, CT11, CT12, CT13, CT14, CT15, CT16, CT17, CT18, CT19, CT20 FROM REPORTS GROUP BY OFFICER
This will display the values of all the case type entries in a record set but I need to count them, I tried to use,
SELECT CT1, CT2, CT3, CT4, CT5, CT6, CT7, CT8, CT9, CT10, CT11, CT12, CT13, CT14, CT15, CT16, CT17, CT18, CT19, CT20 FROM REPORTS COUNT(TSTO) GROUP BY OFFICER
but it just spits an error. I am fairly new to mysql databasing and php, I feel I have a good grasp but query'ing the database and the syntax involved is a tad bit confused and/or overwhelming right now. Just gotta learn the language. I will keep looking and I have found some similar things on here but I don't understand what I am looking at (completely) and I would like to shy away from using code that "works" but I don't understand fully.
Thank you very much :)
Edit -
So this database is an activity report server for the days work for the employees. The person will often open cases during the day. These cases vary in type, and their different types are designated by a four letter convention. So your different case types could be TSTO, DOME, ASBA, etc etc. So the user will fill out their form throughout the day then submit it down to the database. That's all fine :) Now I am trying to build a page which will query the database by user request for statistics of a user's activities. So right now I am trying to generate statistics. Specifically, I want to be able to generate the statistic of, and in human terms, "HOW MANY OCCURENCES OF "USER INPUTTED CASE TYPE" ARE THERE FOR EMPLOYEEIDXXX"
So when a user submits a form they will type in this four letter case type up to 20 times in one form, there is 20 fields for this case type entry, thus there is 20 columns. So these 20 columns for case type will be in one record set, one record set is generated per report. Another column that is generated is the employeeid column, which basically identifies who generated the record set through their form.
So I would like to be able to query all 20 columns of case type, across all record sets, for a defined type of case (TSTO, DOME, ASBA, etc etc) and then group that to corresponding user(s).
So the output would look something like,
316 TSTO's for employeeid108
I hope this helps to clear it up a bit. Again I am fairly fresh to all of this so I am not the best with the vernacular and best practices etc etc...
Thanks so much :)
Edit 2 -
So to further elaborate on what I have going on, I have an HTML form that has 164 fields. Each of these fields ultimately puts a value into a column in a single record set in my DB, each submission. I couldn't post images or more than two URLs so I will try to explain it the best I can without screenshots.
So what happens is this information gets in the DB. Then there is the query'ing. I have a search page which uses an HTML form to select the type of information to be searched for. It then displays a synopsis of each report that matches the query. The user than enters the REPORT ID # for the report they want to view in full into another small form (an input field with a submit button) which brings them to a page with the full report displayed when they click submit.
So right now I am trying to do totals and realizing my DB will be needing some work and tweaking to make it easier to create querys for it for different information needed. I've gleaned some good information so far and will continue to try and provide concise information about my setup as best I can.
Thanks.
Edit 3 -
Maybe you can go to my photobucket and check them out, should let me do one link, there is five screenshots, you can kind of see better what I have happening there.
http://s1082.photobucket.com/albums/j376/hughessa
:)
The query you are looking for would be very long and complicated for your current db schema.
Every table like (some_id, column1, column2, column3, column4... ) where columns store the same type of data can be also represented by a table (some_id, column_number, column_value ) where instead of 1 row with values for 20 columns you have 20 rows.
So your table should rather look like:
officer ct_number ct_value
1 CT1 TSTO
1 CT2 DOME
1 CT3 TSTO
1 CT4 ASBA
(...)
2 CT1 DOME
2 CT2 TSTO
For a table like this if you wanted to find how many occurences of different ct_values are there for officer 1 you would use a simple query:
SELECT officer, ct_value, count(ct_value) AS ct_count
FROM reports WHERE officer=1 GROUP BY ct_value
giving results
officer ct_value ct_count
1 TSTO 2
1 DOME 1
1 ASBA 1
If you wanted to find out how many TSTO's are there for different officers you would use:
SELECT officer, ct_value, count( officer ) as ct_count FROM reports
WHERE ct_value='TSTO' GROUP BY officer
giving results
officer ct_value ct_count
1 TSTO 2
2 TSTO 1
Also any type of query for your old schema can be easily converted to new schema.
However if you need store additional information about every particular report I suggest having two tables:
Submissions
submission_id report_id ct_number ct_value
primary key
auto-increment
------------------------------------------------
1 1 CT1 TSTO
2 1 CT2 DOME
3 1 CT3 TSTO
4 1 CT4 ASBA
5 2 CT1 DOME
6 2 CT2 TSTO
with report_id pointing to a record in another table with as many columns as you need for additional data:
Reports
report_id officer date some_other_data
primary key
auto-increment
--------------------------------------------------------------------
1 1 2011-04-29 11:28:15 Everything went ok
2 2 2011-04-29 14:01:00 There were troubles
Example:
How many TSTO's are there for different officers:
SELECT r.officer, s.ct_value, count( officer ) as ct_count
FROM submissions s JOIN reports r ON s.report_id = r.report_id
WHERE s.ct_value='TSTO'
GROUP BY r.officer