In SSRS, User wants his report parameters selection should be remembered.That is for the first time user will select parameters and somehow next time onward it should remember parameters.
Is it possible to achieve this in any way?? Anybody has any thought on this?
The My Reports feature allows users to build and save their own reports on the server. It also allows them to create linked reports that have parameter defaults set up the way they want. That's the only built-in feature that might get you what you want. It is pretty limited, though, to be honest.
On the other hand, you could build a user parameter storage feature of your own. Here's a rudimentary example.
Start with a table to store your user report parameter values.
create table UserReportParameters (
UserName nvarchar(50),
ParameterSet nvarchar(50),
ParameterName nvarchar(50),
ParameterValue nvarchar(max)
)
Since you're seeking a way to store a user's parameter values, I'll assume you're using some sort of authentication on your reporting service, such as Windows Authentication. We'll be storing the UserName provided by that authentication service along with an arbitrarily named ParameterSet. This ParameterSet value could be the url to the report or some other unique identifier for the report or perhaps a logical name for a set of reports that all use common parameters such as "Sales Reports".
We'll need a way to save these parameter values. A simple stored procedure will do the trick.
create proc SaveUserReportParameter (
#UserName nvarchar(50),
#ParameterSet nvarchar(50),
#ParameterName nvarchar(50),
#ParameterValue nvarchar(max)
)
as
delete UserReportParameters where UserName = #UserName and ParameterSet = #ParameterSet and ParameterName = #ParameterName
insert UserReportParameters select #UserName, #ParameterSet, #ParameterName, #ParameterValue
Now in your report's main dataset query or stored procedure (somewhere you can be sure the code runs once per report execution) you just need to call that stored procedure to store each value.
exec SaveUserReportParameter #UserName, 'Sales Reports', 'StartDate', #StartDate
exec SaveUserReportParameter #UserName, 'Sales Reports', 'EndDate', #EndDate
exec SaveUserReportParameter #UserName, 'Sales Reports', 'DepartmentId', #DepartmentId
exec SaveUserReportParameter #UserName, 'Sales Reports', 'PromoCode', #PromoCode
Note that the table stores everything as nvarchar. I'm being lazy here and letting implicit conversion happen. If you want to store values such as datetime in a specific format, you'll need to convert them when inserting them into the table variable. The #UserName report parameter used here and below should be an internal parameter whose default value is =User!UserId.
Now that we're storing parameters, let's start using them. We'll need another stored procedure. This one's a bit bigger.
create proc GetUserReportParameters (
#UserName nvarchar(50),
#ParameterSet nvarchar(50),
#Columns nvarchar(max)
) as
declare #sql nvarchar(max)
set #sql = '
select * from
(
select
p.ParameterName,
p.ParameterValue
from
(select #UserName UserName, #ParameterSet ParameterSet) stub
left join UserReportParameters p on p.UserName = stub.UserName and p.ParameterSet = stub.ParameterSet
) v
pivot (
min(ParameterValue)
for ParameterName in (' + #Columns + ')
) as pvt'
exec sp_executesql #sql, N'#UserName nvarchar(50), #ParameterSet nvarchar(50)', #UserName, #ParameterSet
And then to call it
exec GetUserReportParameters #UserName, 'Sales Reports', 'StartDate,EndDate,DepartmentId,PromoCode'
As you can see, you provide the UserName and ParameterSet values. The same as you used when you called the save procedure. Here, though, you're also providing a string that's a simple comma separated list of column names. These column names are used by a pivot query to ensure your result set includes columns by those names. You should be aware those columns can and will contain nulls, especially when a user first accesses the report. You should also be aware that all values are nvarchar(max). If you need to parse or convert any values or provide your own defaults when the value is null, you'll need to do some extra work.
In an embedded dataset named UserReportParameters I call the procedure, store the values locally and then do my conversions and null-swapping as necessary.
declare #Parameters table (
StartDate datetime,
EndDate datetime,
DepartmentId int,
PromoCode nvarchar(50)
)
insert #Parameters
exec GetUserReportParameters #UserName, 'Sales Reports', 'StartDate,EndDate,DepartmentId,PromoCode'
select
isnull(cast(StartDate as datetime), dateadd(day,datediff(day,0,getdate()),0)) StartDate,
isnull(cast(EndDate as datetime), dateadd(day,datediff(day,0,getdate()),0)) EndDate,
isnull(cast(DepartmentId as int),15) DepartmentId,
isnull(PromoCode,'FAKESALE') PromoCode
from #Parameters
Now, every time you run the report (more specifically, every time the dataset that contains your call to the save procedure is executed) the parameters you opt to save will be saved. When you leave and come back to the report page, the parameters will be populated with the last values you chose. Note that you don't have to save every parameter value. Just the ones you want to save per-user. You also don't have to use every parameter value that's saved in a given ParameterSet. If you have two sales reports, one that uses PromoCode and one that uses ProductCategory you can save both their parameter values in the 'Sales Reports' parameter set without worry that they'll interfere with one another. Additionally, you could easily create two separate datasets in your report, each pulling a different parameter set. For instance, if PromoCode actually gets saved in the 'Marketing' parameter set and DepartmentId is from the Products parameter set. Once you have this framework, you have a lot of flexibility in how your user parameter defaults get saved.
It is generally considered bad practice to allow reports to alter data. I agree with this conventional wisdom when it comes to domain data. However, this parameter-saving feature is really more of an extension of SSRS functionality, akin to report execution logging. I do not believe it violates the principle.
SCALABILITY -- This will work great for a small number of reports for a relatively small number of users. There could easily be performance issues in larger enterprise environments. (That's why I called this a "rudimentary example" at the start.) You could address this by redesigning the value storage mechanism. For instance, use pre-defined tables for each parameter set instead of dumping them all into a single table so you can avoid pivoting. I'll leave that decision and work to you.
Try this one. It's a bit long, I will just attach the document link here.
Report Parameter Saving Solution
Related
I have a very straightforward SSIS package containing one data flow which is comprised of an OLEDB source and a flat file destination. The OLEDB source calls a query that takes 2 sets of parameters. I've mapped the parameters to Date/Time variables.
I would like to know how best to pass 4 different sets of dates to the variables and use those values in my query?
I've experimented with the For Each Loop Container using an item enumerator. However, that does not seem to work and the package throws a System.IO.IOException error.
My container is configured as follows:
Note that both variables are of the Date/Time data type.
How can I pass 4 separate value sets to the same variables and use each variable pair to run my data flow?
Setup
I created a table and populated it with contiguous data for your sample set
DROP TABLE IF EXISTS dbo.SO_67439692;
CREATE TABLE dbo.SO_67439692
(
SurrogateKey int IDENTITY(1,1) NOT NULL
, ActionDate date
);
INSERT INTO
dbo.SO_67439692
(
ActionDate
)
SELECT
TOP (DATEDIFF(DAY, '2017-12-31', '2021-04-30'))
DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), '2017-12-31') AS ActionDate
FROM
sys.all_columns AS AC;
In my SSIS Package, I added two Variables, startDate and endDAte2018 both of type Date Time. I added an OLE DB Connection manager pointed to the database where I made the above tables.
I added a Foreach Item Enumerator, configured it for Item Enumerator and defined the columns there as datetime as well
I populated it (what a clunky editor) with the year ranges from 2018 to 2020 as shown and 2021-01-01 to 2021-04-30.
I wired the variables up as shown in the problem definition and ran it as is. No IO error reported.
Once I knew my foreach container was working, the data flow was trivial.
I added a data flow inside the foreach loop with an OLE DB Source using a parameterized query like so
DECLARE #StartDate date, #EndDate date;
SELECT #StartDate = ?, #EndDate = ?;
SELECT *
FROM
dbo.SO_67439692 AS S
WHERE
S.ActionDate >= #StartDate AND S.ActionDate <= #EndDate;
I mapped my two variables in as parameter names of 0 and 1 and ran it.
The setup you described works great. Either there is more to your problem than stated or there's something else misaligned. Follow along with my repro and compare it to what you've built and you should see where things are "off"
I want to insert a value to a table in the database using a set of parameters, for which I want to make use of sp_setapprole. I know this sp can be used to set some permissions.
I am not aware how to even start.
My table: XYZ
Parameters: ViewerID, AppID, Key
I want to output Cookie and I want to query the table to delete/update and read a the parameter from another parameter.
check with the below query
DECLARE #cookie varbinary(8000);
EXEC sp_setapprole 'Sales11', 'fdsd896#gfdbfdkjgh700mM'
, #fCreateCookie = true, #cookie = #cookie OUTPUT;
-- The application role is now active.
SELECT USER_NAME();
-- This will return the name of the application role, Sales11.
EXEC sp_unsetapprole #cookie;
-- The application role is no longer active.
-- The original context has now been restored.
GO
SELECT USER_NAME();
-- This will return the name of the original user.
GO
We have a requirement of generating SSRS reports from where we need to convert multi-valued string and integer parameters to datatable and pass it to stored procedure. The stored procedure contains multiple table type parameters. Earlier we used varchar(8000) but it was also crossing the datatype limit. Then we thought to introducing datatable concept. But we were not aware of how to pass values from SSRS.
We found a solution from GruffCode on Using Table-Valued Parameters With SQL Server Reporting Services.
The solution solved my problem, and we're able to generate reports. However, sometimes SSRS returns the two following errors:
An error has occurred during report processing.
Query execution failed for dataset 'DSOutput'.
String or binary data would be truncated. The statement has been terminated.
And
An unexpected error occurred in Report Processing.
Exception of type 'System.OutOfMemoryException' was thrown.
I'm not sure when and where it's causing the issue.
The approach outlined in that blog post relies on building an enormous string in memory in order to load all of the selected parameter values into the table-valued parameter instance. If you are selecting a very large number of values to pass into the query I could see it potentially causing the 'System.OutOfMemoryException' while trying to build the string containing the insert statements that will load the parameter.
As for the 'string or binary data would be truncated' error that sounds like it's originating within the query or stored procedure that the report is using to gather its data. Without seeing what that t-sql looks like I couldn't say why that's happening, but I'd guess that it's also somehow related to selecting a very large number of parameter values.
Unfortunately I'm not sure that there's a workaround for this, other than trying to see if you could figure out a way to select fewer parameter values. Here's a couple of rough ideas:
If you have a situation where users might select a handful of parameter values or all parameter values then you could have the query simply take a very simple boolean value indicating that all values were selected rather than making the report send all of the values in through a parameter.
You could also consider "zooming out" of your parameter values a bit and grouping them together somehow if they lend themselves to that. That way users would be selecting from a smaller number of parameter values that represent a group of the individual values all rolled up.
I'm not a fan of using a Text parameter and EXEC in the SQL statement like the article you referenced describes as doing so is subject to SQL injection. The default SSRS behavior with a Multi-value parameter substitutes a comma-separated list of the values directly in place of the parameter when the query is sent to the SQL server. That works great for simple IN queries, but can be undesirable elsewhere. This behavior can be bypassed by setting the Parameter Value on the DataSet to an expression of =Join(Parameters!CustomerIDs.Value, ", "). Once you have done that you can get a table variable loaded by using the following SQL:
DECLARE #CustomerIDsTable TABLE (CustomerID int NOT NULL PRIMARY KEY)
INSERT INTO #CustomerIDsTable (CustomerID)
SELECT DISTINCT TextNodes.Node.value(N'.', N'int') AS CustomerID
FROM (
SELECT CONVERT(XML, N'<A>' + COALESCE(N'<e>' + REPLACE(#CustomerIDs, N',', N'</e><e>') + N'</e>', '') + N'</A>') AS pNode
) AS xmlDocs
CROSS APPLY pNode.nodes(N'/A/e') AS TextNodes(Node)
-- Do whatever with the resulting table variable, i.e.,
EXEC rpt_CustomerTransactionSummary #StartDate, #EndDate, #CustomerIDsTable
If using text instead of integers then a couple of lines get changed like so:
DECLARE #CustomerIDsTable TABLE (CustomerID nvarchar(MAX) NOT NULL PRIMARY KEY)
INSERT INTO #CustomerIDsTable (CustomerID)
SELECT DISTINCT TextNodes.Node.value(N'.', N'nvarchar(MAX)') AS CustomerID
FROM (
SELECT CONVERT(XML, N'<A>' + COALESCE(N'<e>' + REPLACE(#CustomerIDs, N',', N'</e><e>') + N'</e>', '') + N'</A>') AS pNode
) AS xmlDocs
CROSS APPLY pNode.nodes(N'/A/e') AS TextNodes(Node)
-- Do whatever with the resulting table variable, i.e.,
EXEC rpt_CustomerTransactionSummary #StartDate, #EndDate, #CustomerIDsTable
This approach also works well for handling user-entered strings of comma-separated items.
I have a stored procedure that pulls data for a report. I'm having a problem with the parameters. I have a couple temp tables and some joins that work so I have omitted them below. The problem is this line:
WHERE
SeminarDivision = #SeminarDivision AND SeminarType = #SeminarType
When I put this where clause in to use my seminar parameters the stored proc returns nothing But I need to generate a report based on those two parameters. So where do the parameters go? Can anyone help?
#StartDate DateTime,
#EndDate DateTime,
#SeminarDivision VARCHAR(50),
#SeminarType VARCHAR(50)
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
... OMITTED
SELECT
WL.PID,
CONVERT(varchar(20), upper(substring(FirstName,1,1))+
LOWER(substring(FirstName,2,19))) AS FirstName,
CONVERT(varchar(20), upper(substring(LastName,1,1))+
LOWER(substring(LastName,2,19))) AS LastName,
S.SeminarDivision,
S.SeminarType,
S.StartDate,
S.SeminarLocation
FROM
#tblWaitList WL
INNER JOIN #tblSeminar S ON WL.SeminarGuid=S.SeminarGuid
WHERE
SeminarDivision = #SeminarDivision AND SeminarType = #SeminarType
ORDER BY
LastName,FirstName,StartDate
First and foremost there is nothing wrong with your code, when asking where do these parameters go, they go exactly where you put them. The question is - is the data coming in for SeminarDivision and SeminarType the right type of data? For instance just as a test,
copy the code into a new sql code query inside the editor. Run the command without the where, if you get values great. Now change the where to
WHERE
SeminarDivision = "Possible_Value"
Where Possible_Value should be a possible value...If it returns rows, good...now add the second condition also hardcoding a value:
WHERE SeminarDivision = "Possble_Value" AND SeminarType="Possible_Value_2"
Getting any data? Is it possible you want OR rather then AND ?
There's nothing wrong with the 'location' of your params.
If you're getting no data back, it's either because you've not populated #tblWaiList or #tblSeminar or because the records simply don't match your WHERE clause.
Check your params have the value you think they do by executing print #SeminarDivision etc.
SELECT * FROM #tblSeminar may give you a clue too.
You are not setting parameters correctly for the call.
Try this in SSMS, change values accordingly
EXEC Proc '20110101', '20111101', 'PossibleDivision', 'PossibleType'
If this fails, then show us "OMITTED" code
if this works, show us how you are calling this from the client code
I am using Microsoft sql server 2008, I tried all the 3 solutions, but every time I get the same error
Error at Data Flow Task[OLEDB source[449]]:No colum information was returned by the sql command
I am using the following batch of sql statments to retrieve the server level configuration of all servers in my company. The table variable #tb1_SvrStng has 83 columns and it is populated using different resources.
So I summarize the sql script. I cannot use it as stored procedure because this script is going to run against 14 servers (once for each server). So if I store the procedure on one server, other server cannot execute that procedure in its context.
I will highly appreciate your help. I am not using any temporary table in my script.
declare #tb1_SvrStng table
(
srvProp_MachineName varchar(50),
srvProp_BldClrVer varchar(50),
srvProp_Collation varchar(50),
srvProp_CNPNB varchar(100),
...
xpmsver_ProdVer varchar(50),
..... .
syscnfg_UsrCon_cnfgVal int,
.....
);
insert into #tb1_SvrStng
(
srvProp_BldClrVer,
srvProp_Collation,
srvProp_CNPNB , ........
........ .
)
select convert(varchar, serverproperty('BuildClrVer')),
convert(varchar, serverproperty('Collation'))
........
.......
declare #temp_msver1 table
(
id int, name varchar(100),
...........
);
insert into #temp_msver1 exec xp_msver
Update #tb1_SvrStng
set xpmsver_ProdVer =
(
select value from #temp_msver1 where name = 'ProductVersion'
),
xpmsver_Platform =
(
select value from #temp_msver1 where name = 'Platform'
),
.....
......
select
srvProp_SerName as srvProp_SerName,
getdate() as reportDateTime,
srvProp_BldClrVer as srvProp_BldClrVer,
srvProp_Collation as srvProp_Collation,
.....
.....
from #tb1_SvrStng
From what i can gather from your code and question is that the query cannot be processed outside runtime, because you're doing something dynamic to it, or that it won't process it since it's doing something funky.
One trick to this would be to use the Source component in the data flow task to something "dummy" - which you can fake with a query like this
SELECT
CONVERT(DATATYPE,NULL) AS srvProp_SerName,
CONVERT(DATETIME,NULL) AS reportDateTime,
CONVERT(DATATYPE,NULL) AS srvProp_BldClrVer,
CONVERT(DATATYPE,NULL) AS srvProp_Collation
This way the source component should be able to read the metadata. You can then put your proper query (as long as it's within the limits of the length of the query text) into a variable, and then assign this as an expression to the source component.
At runtime it will then use the expression query - and hopefully don't mind too much the metadata issue.
This may or may not work but it should be worth a try since it won't take long to confirm.