Requirement: I have used grouping on SSRS report 1 parent group and 2 child groups and I Need to display 20 parent level groups per page in report, irrespective of number of rows in child groups rows or parent group rows.
"SSRS Limiting groups per page on SSRS report"
Below how the Dataset and Grouping looks:
Now I need to Display 20 Student records in each page of Report (group StudentID).
Please let me know if anybody aware of solution/faced of this similar type of issue and found solution.
The Dataset's also includes the fields which are in the Row Groups.
This is probably not the most optimised way of doing this, but without seeing your dataset query or stored proc this is the best I can do.
Assuming you dataset query is a simple SELECT and not a stored proc then you can do the steps below. If it is a stored proc, then you can either modify the proc to follow the steps below or dump the results of the stored proc into a temp table in the same way the existing query is shown below.
Taking a simplified version of your data, if you original query was SELECT StudentID, SubjectID, ClientName FROM myTable then we can change this to something like ....
DROP TABLE IF EXISTS #t
CREATE TABLE #t (StudentID INT, SubjectID int, ClientName varchar(50))
INSERT INTO #t
SELECT StudentID, SubjectID, ClientName FROM myTable -- <== YOUR ORIGNAL QUERY OR STORED PROC HERE
SELECT
, ((DENSE_RANK() OVER(ORDER BY StudentID)-1)/20) as myPageNumber
, StudentID, SubjectID, ClientName
FROM #t
The result will give you your original data plus a column that calculates the correct page number (change the /20 if you want to change the number of unique StudentIDs on the page).
Now in the report, right click your outer row group (StudentID) and choose "Add Group => Parent Group", then just choose the myPageNumber field as the field to group by.
This will probably add an extra column to your report, you can delete this , but NOT the group , if prompted.
Finally, right-click your new group in the row group panel, go to "Properties", the "Page Breaks" and set "Between each instance of a group".
That should be it. This is done mainly from memory so it might not be perfect but hopefully should help you get what you want.
Related
My tablix groups on one of its columns and only needs to output a list of time stamps for each row. As the time stamps are only two columns, that leaves an awful lot of wasted space.
Here is a basic mock-up of the current layout...
... and this is the desired layout:
As shown, the report would ideally adjust dynamically to display half the rows of a group in the left "column" (including the extra row if uneven) and the remaining rows in the right "column". Is this possible with SSRS? If not as described, can you suggest something with a similar result?
You can do this with as long as your dataset can be updated to support it.
First I grabbed some sample datetime data I had and inserted it into a table variable called #t. You'll just need to swap out #t for your actual table name. This gave me the following
Then I take this data and workout the row and column the data should sit in. In this example I am using a parameter to define the number of columns I want. You could do this and pass it in from your report if it's helpful, or just change it to a staic value. I'll demo with the parameter being passed in though.
Here's the query (Note you'll need to comment out the #Columns declaration if you want to pass this in from your report but for now we are just testing in SSMS or similar.
-- REPLACE #t with your actual tablename below
DECLARE #Columns int = 2 -- <= comment this out when you copy into your dataset query
SELECT
*
, ColumnNum = ((SortOrder-1) % #Columns) + 1
, RowNum = ROW_NUMBER() OVER(PARTITION BY GroupID, SortOrder % #Columns ORDER BY SortOrder)
FROM(
SELECT
ROW_NUMBER() OVER(PARTITION BY GroupID ORDER BY dt) as SortOrder,
GroupID, dt
FROM #t) x
ORDER BY GroupID, SortOrder
This gives us the following output
Now all we have to do is use a matrix control in the report to display it correctly.
Create a new report
Add a datsource and dataset
Set your dataset query as above remember to comment out the DECLARE #Columns line if you want to parameterise it.
Add a matrix control
Drag RowNum to the 'Rows' placeholder, dt to the 'data' placeholder and finally select ColNum in the columns placeholder
The matrix should look like this (we're not finished yet...)
In the row groups panel, drag GroupID above the exiting row group (above rownum in my example) so it creates a parent group.
Finally, add a blank row inside the RowGroup group by right-clicking the rownum textbox and doing "Insert Row, Inside Group - Below". This will just give us a gap between groups
Note: I've changed the colour of the rownum and columnnum text boxes as we can delete these once testing is complete.
The final design should look like this.
When we run the report and set the parameter to 2 we get this
set it to 3 and we get this
You can now remove the top row and middle column to get rid of the row and column numbers. If you want to have a group header as in your sample. Add a row inside the group again but this time at the top and then add an expression to give your desired title.
My source task has following columns read from csv file:
Sale_id, sale_date, order_no, sale_amt
This is followed by lookup task that looks into the sales sql table (having same column names) and the join is on order_no column.
The issue is that order_no data in sql sale table has value like 'ABC-12345', 'WXYZ-32111' (there are couple of characters prepended to the order number).
Where as in the csv there is '12345' without any characters prepended.
Hence I cannot do a lookup as there is no direct match. Is there any way to remove the characters and the hyphen from sale sql table data (temporarily) for performing the lookup join.
1st Data Flow Task - Use Flat File Source to LookUp and OLE DB Source via SQL Command with the following to LookUp.
select Sale_id, sale_date, order_no, sale_amt,
substring(order_no,charindex('-',order_no,0),len(order_no)) as [key]
from sql sale table
Use [Key] for your look up transformation.
The functions should provide the numeric values you are looking for.
Problem restatement
In your source, you have order numbers coming in that look like numbers. You need to be able to lookup against a source that has a text string prepended to an order number. We can assume the numeric part of the database's order number is unique.
Setup
I created a simplified version of your table and populated it with data
DROP TABLE IF EXISTS dbo.so_66446302;
CREATE TABLE dbo.so_66446302
(
sales_id int
, order_no varchar(20)
);
INSERT INTO dbo.so_66446302
(sales_id, order_no)
VALUES
(1, 'ABC-12345')
, (2, 'WXYZ-32111')
, (3, 'REALLY_LONG-654321');
A critical piece in using Lookup components is getting the data types to agree. I'm going to assume that the order number from the file is a DT_STR and not an integer.
By default, people pick a table in the Lookup component's Connection tab, dbo.so_66446302 but if you check "Use results of a SQL query", you'll have what you're looking for.
Similar query to what Jatin shows below but I find "showing my work" along the way helps me debug when it goes sideways. In this query, that's why I have the intermediate cross apply steps.
SELECT
S.*
, D0.order_no_as_string_digits
FROM
dbo.so_66446302 AS S
CROSS APPLY
(
SELECT
-- Length of the string less where we find the first dash
LEN(S.order_no) - CHARINDEX('-', S.order_no, 1)
)D(dash_location)
CROSS APPLY
(
SELECT RIGHT(S.order_no, D.dash_location)
)D0 (order_no_as_string_digits);
The results of that query are
sales_id order_no order_no_as_string_digits
1 ABC-12345 12345
2 WXYZ-32111 32111
3 REALLY_LONG-654321 654321
Now you can match the derived order number in the database to the one in your file by dragging the columns together. Check any/all columns that you need to retrieve from the database and send the data to the intended destination.
We have a report that outputs Table A. We added Table B to the report model (we added some fields to the report from Table B), which is a many-to-one relationship to Table A. Now when we run the report, we are getting multiple rows, which is to be expected because of the relationship between Table A and Table B.
The problem is, we only want to show on the report the latest record of Table B, based on "creation date".
I tried to set a MAX(!fields.CreationDate)
I found information such as: https://social.msdn.microsoft.com/forums/sqlserver/en-US/2bc16c90-21d6-4c03-a17f-4a5922db76fe/displaying-records-by-max-date-in-ssrs
But when I do something like this, I get a "cannot use aggregate function......" error.
If this was a SQL Statement for TableB, it would be along these lines to display only the most recent record:
SELECT DISTINCT
[ID], [PID], [InputDate], [Changed_Date]
FROM
(SELECT
[ID], [PID], [InputDate], [Changed_Date],
dense_rank() over (partition by PID order by Changed_Date desc) as MyRank
from TableB
) as RankSelect
WHERE MyRank = 1
ORDER BY PID
This gives me the most recent record for TableB. I know technically I could add a view or something to the report model, but I do not want to do this, as another report ran might want a historical of all records in TableB. So I am hoping to somehow incorporate the above results into the report without touching the report model. In which only the latest record from TableB is incorporated into the report.
Would appreciate any help on how we can limit the report to only displaying the latest date record from Table B.
For your table B, set a FILTER for the CreationDate based on the MAX date over the dataset.
This will only display the records where the CreationDate matches the MAX CreationDate from your dataset.
I couldn't find a resolution to filtering the data in the report itself, so I removed TableB from the report model and replaced it with a view of TableB that only returns the most recent record as linked to TableA. Not ideal, as I know at some point they will ask for a report to "show all entries" from TableB, but will cross that bridge later :-)
An SSRS report has multiple parameters, each using it's own stored procedure and dataset. The user first selects a school district from a drop down list. From there, a second drop down populates with the schools in that district.
Once the user picks a school, a third drop down populates with a list of certification dates from which the user can select one. All the queries and drop downs populate correctly.
How to display the most recent date instead of the <Select a Value>?
As an example, for school A, there are three dates from which the user can select one, the most recent being 07/30/2015. The query sorts the dates in Desc order so I want the first one be the default, not <Select a Value>. Rather than go into all the things I've tried, how can this be done?
I usually have a separate dataset for the parameter query and add a MAX column with a subquery to find the latest date.
SELECT DISTINCT CONVERT(VARCHAR(10), checkprintdate, 101) AS CHECK_DATE,
(SELECT CONVERT(VARCHAR(10), MAX(checkprintdate), 101) AS X1
FROM paycheck AS P2) AS MAX_CHECK_DATE
FROM paycheck
ORDER BY CHECK_DATE DESC
I use the CheckDate as the Value and the MaxCheckDate as the Default.
The 'Select a value' (sorry about the missing piece, I didn't realize it wouldn't display with the <>) was the text that was actually showing up in the drop down box, rather than 'ALL' or an empty box. The user should be allowed to select any of the three dates, not just the latest (so I couldn't use the MAX() in the query). But, in any case, I changed the Default values (in the Report Parameter Properties box) on the CertificationDate parameter from 'Specify values' to 'Get values from a query', then put in the dataset name and the field name for the 'Value field'. The most recent date now displays in the drop down box (without the user having to click the down arrow and click on the value). Thanks for the responses.
Say I have a dataset in SSRS called DataSet1 that looks like this:
CREATE TABLE #data
(ID int, Value int, UserID varchar(2))
INSERT INTO #data VALUES
(1, 1000, 'AA'),
(2, 2000, 'AA'),
(3, 3000, 'BB'),
(4, 2000, 'BB'),
(5, 1500, 'BB'),
(6, 1800, 'BB'),
(7, 1700, 'CC')
..and that my report just presents this as a table.
Let's then say I want to add a parameter in that report, that let's the user filter the table by UserID. I want it to be a multiple value parameter where they can choose which users to include in their report. In this case I want the list to be AA, BB and CC.
So far I have done it by creating an extra SQL query based dataset like this:
DataSet1:
SELECT ID, Value, UserID
FROM table
DataSet2:
SELECT DISTINCT UserID
FROM table
And then have the parameter get its available values from DataSet2. However the query I have in my particular report is a very long and complex query, that I would prefer to not use in two datasets. If I have to go back and change something in the query, I would have to maintain that in two places, and so on.
In short: Is there a way to have the available values of my parameter by something like this:
SELECT DISTINCT UserID FROM DataSet1
Thanks!
I decided to write my comment on your answer, M.Ali, as an answer to my own question, as I found a way to solve this. Maybe I didn't explain my problem precisely enough. I am aware of how the above thing works, and how to pass parameters based on one dataset, down thru the SQL to create another dataset, multiple values allowed or not. I appreciate your answer though!
The problem I have is that the query that would define my list of values for the parameter, and the query for the actual dataset, are the same. And it's a HUGE query. In other words, where it says 'TABLE' in the code sample, I have several hundreds of lines of code. And my goal was to not have this whole query be defining both datasets. If I in the future have to change the query, I would have to do it in more than one place. Here's how I solved it:
I placed the main query in a shared dataset instead of embedding it into my report. And I then added a row_number function to my query like so:
SELECT ID, Value, UserID, rn = ROW_NUMBER() OVER(PARTITION BY UserID ORDER BY UserID)
FROM *my huge query*
This means that there is only one 'rn = 1' row per UserID. Then I went back to my report. My original DataSet1 would then just point to the shared dataset. The DataSet2 (the parameter one) would also point to the shared dataset with the one difference that I added a filter to that dataset saying 'rn = 1'. I then made a parameter with 'allow multiple values' that took its values from DataSet2. And it works like a charm. This way I can just go to the shared dataset when I need to update the query, and both DataSet1 and DataSet2 will be updated accordingly!
Success :)
Again, thanks for your answer!
You will have to have a separate data set for your parameter query and yes you got that part right, for the given data set:
SELECT DISTINCT UserID
FROM TABLE
This query will be used to populate the drop down list of your parameter. (Multiple values allowed or not).
For you Main query:
if you allow Multiple Selection for #UserID parameter you will write you main Data set query with IN operator as below:
SELECT ID, Value, UserID
FROM table
WHERE (UserID IN (#UserID))
If you only want users to be able to select only one value at a time the you can write the above query with a where clause something like WHERE UserID = #UserID.
Make sure you map the variables correctly. But you will have to have a separate query for your drop down list.