I have a program that fills 2 tables in SQL db, let's call them tUser and tItems.
tItems will contain 3 rows with a piece field, while tUser will contain 1 row with totalNoOfPieces field.
I have created a report in MS Report Builder 3.0 that shows whatever I need to, adding both those tables into my dataset, and one of the expressions there should show me Piece 1 of 3 using the above fields, for example.
I'm currently using
=CStr(First(Fields!piece.Value, "DataSet1")) + " of " + CStr(First(Fields!totalNoOfPieces.Value, "DataSet1"))
How would I make it so RB generates totalNoOfPieces identical reports for me, where the only thing that changes is the Piece x of y part?
(I guess what I'm asking is how to do it so I get 3 reports that would represent
SELECT * FROM tItems
INNER JOIN tUser ON tItems.ID=tUser.ID
in those reports)
EDIT: I should specify, I know I can add a parameter and make available values be SELECT piece FROM tItems but I'm wondering how to auto generate report for all available values.
Create a version of your report that accepts two parameters say, #CurrentPiece and #TotalPieces plus any other parameters you currently require. You don't need to setup available values for the parameters as the user will never use this report directly.
Test the report works manually by typing the parameter values in
Create a new new report that accepts a parameter #TotalPieces, plus anything else you currently need to pass to the report in step 1.
Create a dataset (say dsLoop) and set it's query definition to be the following:
dsLoop query:
DECLARE #counter int = 1
DECLARE #t TABLE (PieceNum int)
WHILE #TotalPieces>= #counter
BEGIN
INSERT INTO #t SELECT #counter
SET #counter = #counter +1
END
SELECT * FROM #t ORDER BY rownum`
Add a Matrix to your report and set the dataset property to dsLoop
Drag PieceNum from the dataset field list to the cell that says "Columns" (top right cell of matrix). This will create a column group grouped and sorted by PieceNum
In the data cell, insert a subreport and set the subreport name to be the report you created in step 1
Set the #CurrentPiece parameter of the subreport to be PieceNum (from the dataset) and set the #TotalPieces parameter to be loop report's #TotalPieces parameter.
Set any additional parameters that your subreport requires.
Set the column width to suit.
This should now give you a working report, you'll just need to tidy up/adjust anything not quite right.
If this is not clear let me know and I'll do a mock-up so you can see it in action.
Related
My SSRS report has one dataset (datasetMacys) that calls usp_GetStoreSales #Rundate, #StoreName.
Can the dataset have a default value? That way the report will only ask for one parameter (#Rundate) and the dataset has the string value "Macys" embedded?
In other words, the user will not have to select a value for the second parameter because it's already the default value of that dataset.
I would then add a 2nd dataset (datasetSears) where the default value for #StoreName is "Sears", which means it will only use the #Rundate that the user selected.
The stored procedure looks like this, even though it's not really needed for the question:
create procedure usp_GetStoreSales
(
#RunDate date,
#StoreName varchar(10)
)
as
select * from [Sales]
where RunDate = #RunDate and StoreName = #StoreName
I can easily fix this problem by creating two different stored procedures (ie. usp_GetMacysSales #RunDate and usp_GetSearsSales #RunDate), but that's exactly what I want to avoid.
You just need to create your two datasets and then, for each dataset, righ click the dataset name, choose properties, click the parameters tab and overwrite the parameter value for the StoreName parameter.
Yes - you can have a default value for the parameter of a dataset.
In the Parameters tab of the Dataset Properties, you can type in (hard code) a value in the Parameter Value expression box.
Of course the next question would be WHY? There may be better ways to do it.
If you are going to have both sets of data, why not make a query that combines the data into one so you only have one dataset?
I want to create a report in MS SQL Server BIDS (SSMS and Visual Studio). The user would enter a list of email addresses as a parameter. So #pEmails would be 'foo#bluh.com', 'bar#meh.org', etc. These email addresses may or may not be in a table.
I can simply do:
and Table.Email in (#pEmails)
and that works, except I need to return the email address if it's NOT found as well. So the results would be something like:
|email |found in table|
|------------|--------------|
|foo#bluh.com| Y |
|bar#meh.org | N |
I was thinking I could take the list of values entered as the #pEmails parameter and create a temp table with them, which I could then left join with, but my attempts to do so have not worked out.
declare #pEmails table (EmailAddress varchar(255));
insert into #pEmails values (#ReportParameter1);
select
*
from
#pEmails
The above works if only a single value is put into #ReportParameter1, but not if multiples are in it.
I am using SQL Server 2008. Any suggestions on how best to proceed?
As has been stated, you need some kind of split function, for analysis on the performance of various methods Split strings the right way – or the next best way is an excellent read. Once you have your function, you then need to define your query parameter as a string, rather than a table:
So your query would actually become:
DECLARE #pEmails TABLE (EmailAddress varchar(255));
INSERT #pEmails (EmailAddress)
SELECT Value
FROM dbo.Split(#pEmallString);
Then go to your dataset properties, and instead of passing the multivalue parameter #pEmails to the dataset, instead create a new one #pEmailString, and set the value as an expression, which should be:
=Join(Parameters!pEmails.Value, ",")
This turns your multivalue parameter into a single comma delimited string. It seems pretty backwards that you need to convert it to a delimited string, only to then split it in SQL, unfortunately I don't know of a better way.
Here are some learnings on this topic (standing on the shoulders of the information elsewhere in this thread).
Set a parameter (select 'multiple values' checkbox):
InputList
Establish dataset query:
SELECT *
INTO #InputTemp
FROM STRING_SPLIT(#InputListJoin, ',')
SELECT value as ValueName
FROM #InputTemp T2
WHERE NOT EXISTS (
SELECT MyValue
FROM MyTable T1
WHERE T1.MyValue = T2.value
)
Establish dataset parameters:
Name: #InputList | Value: [#InputList]
Name: #InputListJoin | Value(expression): =Join(Parameters!InputList.Value,",")
The element names can be changed as needed.
Somewhat on topic, other details that might be helpful:
[#InputList.IsMultiValue] --> true/false whether your parameter is multi-value (not whether there are multiple values)
[#InputList.Count] --> count of items in input list (excludes blank lines)
=Parameters!InputList.Value(2) --> return third value from list (counting from zero)
I've read countless posts on this topic but I can't seem to get any of the recommendations to apply to my particular situation (which isn't different than others...)
I have an SSRS report. Dataset 1 is using a stored procedure and in the where clause I have
and (#param is null or alias.column in
(select Item from dbo.ufnSplit(#param,',')))
I borrowed the dbo.ufnSplit function from this post here: https://stackoverflow.com/a/512300/22194
FUNCTION [dbo].[ufnSplit]
(#RepParam nvarchar(max), #Delim char(1)= ',')
RETURNS #Values TABLE (Item nvarchar(max))AS
--based on John Sansoms StackOverflow answer:
--https://stackoverflow.com/a/512300/22194
BEGIN
DECLARE #chrind INT
DECLARE #Piece nvarchar(100)
SELECT #chrind = 1
WHILE #chrind > 0
BEGIN
SELECT #chrind = CHARINDEX(#Delim,#RepParam)
IF #chrind > 0
SELECT #Piece = LEFT(#RepParam,#chrind - 1)
ELSE
SELECT #Piece = #RepParam
INSERT #Values(Item) VALUES(#Piece)
SELECT #RepParam = RIGHT(#RepParam,LEN(#RepParam) - #chrind)
IF LEN(#RepParam) = 0 BREAK
END
RETURN
END
In dataset 2 I am getting the values that I want to pass to dataset 1
select distinct list from table
My parameter for #param is configured to look at dataset 2 for available values
My issue is that if I select a single value from my parameter dropdown for #param, the report works. If I select multiple values from the dropdown, I only return data for the first value selected.
My values in dataset 2 do not contain any ,'s
Did I miss anything for fail to provide enough information? I'm open to criticism, feedback, do's and don'ts for this, I've struggled with this issue for some time, and by no means a SQL expert :)
Cheers,
MD
Update So SQL Profiler is showing me this:
exec sp... #param=N'value1,value2 ,value3 '
Questions are:
1. Shouldn't every value be wrapped in single quotes?
2. What's with the N before the list?
3. Guessing the trailing spaces need to be trimmed out
When you select multiple values from a parameter dropdown list they are stored in an array. In order to convert that to a string that you can pass to SQL you can use the Join function. Go to your dataset properties and then to the Parameters tab. Replace the Parameter Value with this expression:
=Join(Parameters!param.Value, ",")
It should look like this:
Now your split function will get one comma separated string like it's supposed to. I would also suggest having the split function trim off spaces from the values after it has separated them.
So I figured it out and wanted to post my results here in hopes it helps someone else.
Bad data. One trailing space was blowing up my entire result set, and I didn't notice it until I ran through several scenarios (choosing many combinations of parameters)
My result set had trailing spaces - once I did an rtrim on it I didn't have to do any fancy join/split's in SSRS.
I opened a report I started in BIDS in MS SQL Server Report Builder 3.0, as I read an answer here on SO that said that was the easiest way to create a table containing all the values in a Dataset.
So I opened my .rdl file there, selected the Insert tab, then Table > Table Wizard, and the dataset from the "Choose an existing dataset in this report or a shared dataset" list.
When I select the "Next" button of the wizard, though, all lists are empty (Available fields, Column groups, Row groups, Values).
If I select "Next" again, I get, "The values field list must contain at least one field."
Those are auto-populated, though, and, as written above, are as empty as a politican's brain.
Is it because my dataset is a StoredProc, and returns data from a temp table? If so, is there a workaround?
Note: I also tried the Matrix > Matrix Wizard, with the same results.
UPDATE
Also and doubtless relatedly (no pun intended), when I try to run the report from within ReportBuilder, I see:
What a revoltin' development!
UPDATE 2
And when I return to BIDS to work on the project and try to add an Expression in a Matrix, in the Edit Expression dialog, on selecting the Dataset of interest, I get, " dataset has no fields."
Ay, caramba!
UPDATE 3
In response to lrb's answer: I don't know if my SP is really unparseable or not; it does return values from a temp table - Here is the end of it:
SELECT PLATYPUSDESCRIPTION, WEEK1USAGE, WEEK2USAGE, USAGEVARIANCE,
WEEK1PRICE, WEEK2PRICE, PRICEVARIANCE, PRICEVARIANCEPERCENTAGE
FROM #TEMPCOMBINED
ORDER BY PLATYPUSDESCRIPTION;
Could that (using a temp table) be the problem?
UPDATE 4
When adding an Expression to a textbox like so:
=Fields!PLATYPUSDESCRIPTION.Value
...I get the following fingerwag on the Preview tab:
The definition of the report 'bla' is invalid. The Value expression for the textbox 'textbox4' refers to the field 'PLATYPUSDESCRIPTION'. Report item expressions can only refer to fields within the current data set scope or, if inside an aggregate, the specified data set scope.
Surely there's a way to use results from temp tables in an SSRS report, no es cierto?
This will happen when the query or stored procedure can not be parsed with certainty. For example, if your data set is a store procedure that returns something like the following:
IF(#SomVariable=1)
SELECT 1,2,3,4
ELSE
SELECT 'A','B','C'
The above logic in a SP would be horrible, however, the field name and datatypes can not be determined. The same holds true in other edge case scenarios.
What you can do for a work around is to trick the parser by modifying your sp and offering up a clean return statement, then changing the sp back to its original form. Since the metadata is persistent until the next refresh, your values will hold. NOTE : If the problem occurs when returning temporary tables in your dataset see #4 below.
1. Modify your existing stored procedure
ALTER PROCEDURE MyProcedureThatDoesNotParse()
AS
BEGIN
/*COMMENT OUT CURRENT SP LOGIC
...
*/
SELECT
MyField1=1,
MyField2='String',
MyField3=0.01
END
2. IN SSRS Refresh the fields for your dataset.
NOTE : You will see MyField1,MyField2 and MyField3 in the fields list.
3. Revert the changes to your stored procedure.
4. For queries or SP's that return a local #temporary table, global ##temporary table or a table valued #variable, it seems that aliasing the temp structure works. I.E
SELECT * FROM #TABLE --Does not always parse in SSRS
SELECT * FROM #TABLE T --Seems to be able to be parsed by SSRS
Change command type on the report builder, choose " text " and write exec yourprocedurename. It will work
I have two datasets namely Dataset1 and Dataset2.
Dataset1 is a query type of "Stored Procedure". The sp "TestProcpk" is selected and parameter "value" is mapped to it.
TestProcpk query:
Create procedure TestProcpk #value varchar(20)
as
insert into testProc select #value
Dataset2 uses the above table as below (Dataset2 fields are used in the report display):
select value from testProc
where value = #value
Expected
Note: table "testProc" is empty.
While running the report I select parameter value as "ABC". The report should display value "ABC".
Why Dataset2 is not reflecting the value "ABC" in same time? Any other workaround to achieve this.
Thanks
I believe your problem is due to SSRS running the transaction in parallel. The table isn't created from Dataset 1 when Dataset 2 is run.
In the Datasource Properties, on the General tab there is a setting for Use single transaction when processing queries. This forces the queries to run one at a time in a single transaction (great for using temp tables). Check this box and it should work as you expect. It will execute in the order of your datasets (top down).
For more info:
http://blogs.msdn.com/b/robertbruckner/archive/2008/08/07/dataset-execution-order.aspx