Interactive sorting In SSRS on Values - Matrix report - reporting-services

I want a interactive sorting in SSRS matrix report. From database we are getting 3 columns -PrimaryKey,Columns and Value.
We are grouping rows by Primary Key and grouping column by Columns and use Value as data.
My Matrix Report -
ID [Columns]
[Primary Key] Values
Output of the Matrix report -
ID FirstName MiddleName Lastname
1 Rajiv Jha Sharma
2 Prem Kumar Bose
3 Usha Shamila Praveena
I am able to use the interactive sorting on ID because ID is group by rows but I want to use the interactive sorting on dynamic cloumns values like FirstName,MiddleName and LastName.
Expected result when we interactive sort on Lastname
ID FirstName MiddleName Lastname
2 Prem Kumar Bose
3 Usha Shamila Praveena
1 Rajiv Jha Sharma
Thanks for any Help.

Are you using the report wizard to build this? You should be able apply the interactive sort using the properties menu on the column groups.
By adding an interactive sort button to a column header you can allow a user to click the column header and sort the parent group rows in a table or matrix by the value displayed in that column. The order of child groups remains unchanged.
To add an interactive sort button to a column header to sort groups:
In a table or matrix on the report design surface, right-click the text box in the column header for the group to which you want to add an interactive sort button.
Click Text Box Properties.
Click Interactive Sort.
Select Enable interactive sort on this text box.
In Sort, click Groups.
From the drop-down list, select the name of the group that you are sorting. For groups based on simple group expressions, the Sort by value is populated with group expression.
For more info, see this article: http://technet.microsoft.com/en-us/library/cc627509(v=sql.100).aspx

Quite an old question, but I stumbled upon similar problem recently.
Though SSRS does not allow you to add interactive sorting on dynamic columns in a matrix, you can simulate similar behaviour. I've figured out a method, which require the report to fire itself (through go to report action) sorted on desired column.
I will use a bit more complicated example to show the full functionality of this solution.
Imagine an online bookstore, which would like a report showing their customers (rows), number of books (values) and total value of books (values), which they bought, by category – Fiction/NonFiction in my example (columns). Of course they want to see their best customers, so the sort will be descending.
Example data that we are getting from the database:
UserID Columns BooksCount BooksValue
AliBaba Fiction 2 25.96
AliBaba NonFiction 4 112.00
ThomasJefferson Fiction 3 36.83
ThomasJefferson NonFiction 1 46.80
BillCosby Fiction 10 536.47
BillCosby NonFiction 2 26.87
The report will look like this:
[Columns]
Books Count Books Value
[UserID] Values Values
I would like the report to be able to sort by “Books Count” or “Books Value” for any Column. Here are the steps to follow:
You need to add parameters that will store the name of the column to sort on - #SortColumn and the metric name (counts or values) to sort on - #SortMetric.
Go to “Books Count” textbox and add action "Go to report" specifying the same report. Add #SortColumn parameter with a value from [Columns] field in the underlying dataset. Add #SortMetric parameter with value set to “BooksCount”. Similar for “Books Value” textbox.
You can adjust the column header text with following expression, which will show the user on which column data is sorted:
= IIf( Parameters!SortColumn.Value=Fields!Columns.Value And Parameters!SortMetric.Value = "BooksCount" ," ^","")
This was for “Books Count”, you can add similar for “Books Amount”
Finally the magic that happens on the database site. Source table is named [Sales]. Apart from the sorting, below code allows to select only top N rows if your dataset is larger.
You can create a dataset using this code or better create a stored procedure. And join report parameters with dataset parameters.
DECLARE #TopN INT = 50
;WITH Users_Sorted AS
(
SELECT
UserID
,ROW_NUMBER() OVER (ORDER BY
CASE #SortMetric
WHEN 'BooksCount' THEN Sales.BooksCount
WHEN 'BooksValue' THEN Sales.BooksValue
END DESC) AS ROWNO
FROM Sales
WHERE
Sales.Columns = #SortColumn
)
,Sales_MAIN AS
(
SELECT
Sales.UserID
,Sales.Columns
,Sales.BooksCount
,Sales.BooksValue
,ISNULL(Users_Sorted.ROWNO,
ROW_NUMBER () OVER (PARTITION BY Sales.Columns ORDER BY Sales.UserID ASC)
) AS ROWNO
FROM Sales
LEFT JOIN Users_Sorted ON Sales.UserID = Users_Sorted.UserID
)
SELECT * FROM Sales_MAIN WHERE ROWNO <= #TopN ORDER BY ROWNO

Related

SSRS Report - Badges

Is there an easy way to do a page of badges in an SSRS report? I am looking at 2 across and 3 down per page based on a list. I have built one so far of a single column using a list box but the problem is that it is not advancing to the next record and shows me the same record over and over until I get to the end of the count of total records in the dataset so I know I am doing something wrong. I am using Visual Studio 2017
I use a matrix when I am making a grid with boxes that go across and down.
First I add a ROW_NUMBER to the query to have the order in which to show the records. I subtract 1 so the values start with 0.
SELECT *, ROW_NUMBER()OVER(ORDER BY EFF_DATE) - 1 ROW_NUM
FROM BLAH_BLAH...
Then in SSRS, add 2 Calculated Fields to the dataset with the ROW_NUM.
The first is named ROW. It will have an integer with the row that the record will end up in.
=INT(Fields!ROW_NUM.Value / 2)
The second is COLUMN that will give the a column number.
=Fields!ROW_NUM.Value MOD 2
Then in the matrix, set the grouping based on the calculated fields.
COLUMN GROUP
Group and Sort by COLUMN
ROW GROUP
Group and Sort by ROW
The 2 can be changed to use whatever number of columns is needed.

SSRS 2012 Dynamic Column Number

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.

SQL into Table Multiple queries same column

I am trying to create a web based report to show the response of certain advertisements.
$sql1 = "
SELECT date
, source
, source_desc
, COUNT(ordernumber) count
, SUM(ordervalue) value
, type
FROM dailystats
WHERE client = '$client2'
AND event <> 'B02'
AND date BETWEEN '$start' AND '$end'
GROUP
BY source
ORDER
BY source;
";
This works fine for my table to show total values, but I want to break it down further. I currently have SOURCE {source}, DESCRIPTION {source_desc}, TOTAL ORDERS {count}, TOTAL ORDER VALUE {value}, as my headers which are populated by the above fields.
I want, as well as the current totals, to include further columns when the field "TYPE" is "P", "T" and "E". I want this to leave me with data to fill new headers (when I put them into the table) consisting of SOURCE, DESCRIPTION, WEB ORDERS, WEB ORDER VALUE, PHONE ORDERS, PHONE ORDER VALUE, POST ORDERS, POST ORDER VALUE, TOTAL ORDERS, TOTAL ORDER VALUE.
I need to create the data for the new headers, so WEB ORDERS will give me the total orders with the TYPE "E". On its own this would be something like COUNT(ordernumber) count where type = "E", but I need multiple of these and I cannot get it to work.
It currently looks like this :
|Source|Source Description|Total Orders|Total Order Value|
|DM1 |Daily Mail 1 |500 |5,000 |
I want to retain this information, but add in as described above, to look like this.
|Source|Source Description|Web Orders|Web Order Value|Post Orders|Post Order Value|Mail Orders|Mail Order Value|Total Orders|Total Order Value|
|DM1 |Daily Mail 1 |100 |1,000 |300 |3,000 |100 |1,000 |500 |5,000 |
I hope I have explained my problem adequately.
use group_concat(type) as type in your code.
(if it is wrong sry. pls explain it clear)
I want this to leave me with headers (when I put them into the table) of SOURCE, DESCRIPTION, WEB ORDERS, WEB ORDER VALUE, PHONE ORDERS, PHONE ORDER VALUE, POST ORDERS, POST ORDER VALUE, TOTAL ORDERS, TOTAL ORDER VALUE.
If i understand correctly you want to add headers to your result ? this should be done by:
SELECT column_name(s)
FROM table_name AS alias_name;

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.

How do I write report from 2 different dataset linked by ID?

I am building a report in report builder. I have 2 dataset, they can't be merged because of their complexity. What I would like to do is make a report where it use the ID from the first dataset to look up data in the 2nd dataset. Is this possible? The following are example, not exact code, but what I need:
First Dataset:
select itemID from Items
Second Dataset:
select itemID, saleAmount, salePrice from Sales
I would like to setup my report like this:
ItemID | Sale Count | Sale Price
--------------+-------------------------------------------------------------+------------
Items.itemID | sum(Sales.saleAmount) where items.itemID = Sales.itemID | sum(Sales.salePrice ) where items.itemID = Sales.itemID
So the end result will be like this:
ItemID | Sale Count | Sale Price
--------------+-------------------------------------------------------------+------------
1 | 11223 | $123123
2 | 4537 | $8375
Is this possible? Maybe with Conditional Lookup?
It's a shame you can't join the data when creating the datasets.
Failing that, I can think of a couple of other options:
Use LookupSet and custom code
This excellent answer How to combine aggregates within a group with aggregates across groups within SSRS has a perfect example of how you might do this.
Basically, you add custom code in a function (e.g. SumLookup) that accepts the results of a LookupSet call and returns the aggregated value. You'd have expressions like the following in your report:
=Code.SumLookup(
LookupSet(Fields!itemID.Value, Fields!itemID.Value, Fields!saleAmount.Value, "Sales")
)
I created a quick test and it works perfectly.
Use subreports
To do this you'd create table based on the Items dataset, then in the detail row you'd embed a subreport to display the Sales information.
The subreport would need an itemID parameter to filter the Sales appropriately, you would set the parent table to pass =Fields!itemID.Value to the subreport - this would then repeat for each itemID row and display the relevant Sales data.
For what it's worth, I'd look at the first option - there is some custom code, but it's straightforward, and that way you wouldn't need to deploy multiple reports. Just seems cleaner to me.