Dynamically create filename in SSRS 2008 - reporting-services

I have been asked a couple times to change the file name dynamically in SSRS 2008. Example: ReportName_201101.RDL. The 201101 represents the execution date. Can this be accomplished in SSRS 2008?

If you mean the filename when you export the report and also happen to be pulling it from the ASP.NET ReportViewer, you can set the name through the DisplayName property.
ReportViewerControl.ServerReport.DisplayName = "ReportName_201101";
or (if ProcessingMode is Local):
ReportViewerControl.LocalReport.DisplayName = "ReportName_201101";
For pretty much all other cases, Alison is right.

There is an MS Connect item open for this. It only has a few votes, so head over there and upvote it...

Another work around, is to rename the report before it runs automatically. This is a diamond in the rough. This may only work for reports that are subscriptions and not ones that users link back to.
Create a table on the ReportServer database that contains a listing of all reports that you want to rename before they execute.
Table Report_Rename_Listing
RenameID int
ItemID uniqueidentifier
OriginalReportName nvarchar(350)
DateType nvarchar(75)
Format int
DatePlusMinus real
Create a stored procedure on the same server that goes out and changes all the reports in the above table.
Create Procedure [dbo].[RenameReports]
AS
SET NOCOUNT OFF ;
Update dbo.Catalog
Set Name = ISNULL(( Select OriginalReportName + '_' +
dbo.func_SetupRenameOfReports(DateType, Format, DatePlusMinus)
From dbo.DDC_Report_Rename r
Where r.ItemID = c.ItemID), Name)
From dbo.Catalog c
return (0)
Create a scalar function on same server that figures out just how you want to rename the report.
Create Function [dbo].[func_SetupRenameOfReports]
( #DateType nvarchar(75), #Format int, #PlusMinus real )
RETURNS nvarchar(75)
AS
BEGIN
Declare #FirstMonth datetime, #LastMonth datetime
Declare #OutputFormat nvarchar(75)
Set #FirstMonth = CONVERT(datetime, Convert(varchar(2), DateAdd(mm, #PlusMinus, GetDate()), 103) + '/1/' + CONVERT(varchar(4), DateAdd(mm, #PlusMinus, GetDate()), 102))
Set #LastMonth = DATEADD(dd, -1, DateAdd(mm, 1, #FirstMonth))
Set #OutputFormat =
Case When #DateType = 'CurrentDate' Then Convert(varchar(75), DateAdd(dd, #PlusMinus, GetDate()), #Format)
When #DateType = 'CurrentDayName' Then CONVERT(varchar(75), DateName(dw, DateAdd(dd, #PlusMinus, GetDate())))
When #DateType = 'CurrentMonthName' Then CONVERT(varchar(75), DateName(mm, DateAdd(mm, #PlusMinus, GetDate())))
When #DateType = 'CurrentYear' Then CONVERT(varchar(75), DateAdd(yy, #PlusMinus, GetDate()))
When #DateType = 'CurrentBeginEndMonth' Then CONVERT(varchar(10), #FirstMonth, #Format) + '-' + CONVERT(varchar(10), #LastMonth, #Format)
End
If #OutputFormat IS null
Begin
Set #OutputFormat = ''
End
Return #OutputFormat
END
Then setup this up to have the stored procedure automatically run daily on your server. I have it run just after midnight every day.

Unfortunately, no, it is not possible. It is another one of those features that is missing from SSRS that developers have been asking for.

Here is a correction to the above stored procedure so that it actual works.
ALTER PROCEDURE [dbo].[ddc_RenameReports]
AS
SET NOCOUNT OFF ;
Update dbo.Catalog
Set Name = ISNULL((Select OriginalReportName + '_' +
dbo.func_SetupRenameOfReports(DateType, Format, DatePlusMinus)
From dbo.DDC_Report_Rename r
Where r.ItemID = c.ItemID And r.Active = 1), Name)
From dbo.Catalog c
Update c
Set c.Path = ISNULL((Select c2.Path + '/' + OriginalReportName + '_' +
dbo.func_SetupRenameOfReports(DateType, Format, DatePlusMinus)
From dbo.DDC_Report_Rename r2
Where r2.ItemID = c.ItemID AND r2.Active = 1), c.Path)
From dbo.Catalog c
inner join dbo.Catalog c2 on c2.ItemID = c.ParentID
return (0)

Related

Executing SQL with parameters in SSIS

How do I execute the SQL script below a SSIS project? I've tried setting up parameters & variables; however.... nothing I do seems to pass the parameters via SSIS
declare #businessunit varchar(255) = 'Test'
declare #advisor varchar(255) = 'Smith'
declare #iuid int =
(
select U.[iuid]
from U
inner join [dbo].A on u.[ipartyid] = A.[iuserid]
inner join [dbo].B on A.[ibusinessunitid] = B.[ipartyid]
inner join [dbo].C on u.[ipartyid] = C.[ipartyid]
inner join [dbo].D on C.[ipartyid] = D.[ipartyid]
where 1 = 1
and B.[name] = #businessunit
and D.[lastname] = #advisor
)
select HHName
,HHID = h.ihhid
,FNAME =
case
when charindex(',', h.vhhname) > 0 and trim(substring(h.vhhname, patindex('% i%', h.vhhname), len(h.vhhname))) in ('i', 'ii', 'iii')
then concat(dbo.Propercase(concat(trim(substring(trim(substring(h.vhhname, charindex(' ', h.vhhname), len(h.vhhname))), 1, charindex(' ', trim(substring(h.vhhname, charindex(' ', h.vhhname), len(h.vhhname)))))), ' ', trim(substring(h.vhhname, 1, (charindex(',', h.vhhname) - 1))))), UPPER(substring(h.vhhname, patindex('% i%', h.vhhname), len(h.vhhname))))
when charindex(',', h.vhhname) > 0 and nullif(h.vdescr, '') is null
then dbo.Propercase(replace(replace(concat(trim(substring(h.vhhname, (charindex(',', h.vhhname) + 1), len(h.vhhname))), ' ', trim(substring(h.vhhname, 1, (charindex(',', h.vhhname) - 1)))), '+', '&'), ' and ', ' & '))
else dbo.Propercase(replace(isnull(nullif(h.vdescr, ''), h.vhhname), ' and ', ' & '))
end
,RepNo = h.planid
from [dbo].[HH] h
inner join
(
select u.[usertype]
,a.[user_planid]
from [dbo].users u
inner join [dbo].user_access a on u.iuid = a.iuid
where 1 = 1
and u.[usertype] <> 'e'
and u.iuid = #iuid
group by u.[usertype],a.[user_planid]
) p
on h.[planid] = p.[user_planid]
I'm going to assume you already have two SSIS variables that correspond to #businessunit and #advisor and they are being populated with the correct values already.
You can use an Execute SQL Task with parameter mapping to run your query. First thing you want to do is open the task editor, and configure your db connection. Next, hit the three dots next to SQLStatement to pull up the query editor window. Now you can start transposing your query, with a few modifications. I find that the Execute SQL Task works best when you separate variable declaration and assignment statements. You can use the following as your query text:
declare #businessunit varchar(255)
declare #advisor varchar(255)
declare #iuid int
SET #businessunit = ?
SET #advisor = ?
SET #iuid =
(
select U.[iuid]
from U
inner join [dbo].A on u.[ipartyid] = A.[iuserid]
inner join [dbo].B on A.[ibusinessunitid] = B.[ipartyid]
inner join [dbo].C on u.[ipartyid] = C.[ipartyid]
inner join [dbo].D on C.[ipartyid] = D.[ipartyid]
where 1 = 1
and B.[name] = #businessunit
and D.[lastname] = #advisor
)
select HHName
,HHID = h.ihhid
,FNAME =
case
when charindex(',', h.vhhname) > 0 and trim(substring(h.vhhname, patindex('% i%', h.vhhname), len(h.vhhname))) in ('i', 'ii', 'iii')
then concat(dbo.Propercase(concat(trim(substring(trim(substring(h.vhhname, charindex(' ', h.vhhname), len(h.vhhname))), 1, charindex(' ', trim(substring(h.vhhname, charindex(' ', h.vhhname), len(h.vhhname)))))), ' ', trim(substring(h.vhhname, 1, (charindex(',', h.vhhname) - 1))))), UPPER(substring(h.vhhname, patindex('% i%', h.vhhname), len(h.vhhname))))
when charindex(',', h.vhhname) > 0 and nullif(h.vdescr, '') is null
then dbo.Propercase(replace(replace(concat(trim(substring(h.vhhname, (charindex(',', h.vhhname) + 1), len(h.vhhname))), ' ', trim(substring(h.vhhname, 1, (charindex(',', h.vhhname) - 1)))), '+', '&'), ' and ', ' & '))
else dbo.Propercase(replace(isnull(nullif(h.vdescr, ''), h.vhhname), ' and ', ' & '))
end
,RepNo = h.planid
from [dbo].[HH] h
inner join
(
select u.[usertype]
,a.[user_planid]
from [dbo].users u
inner join [dbo].user_access a on u.iuid = a.iuid
where 1 = 1
and u.[usertype] <> 'e'
and u.iuid = #iuid
group by u.[usertype],a.[user_planid]
) p
on h.[planid] = p.[user_planid]
Hit OK in the query editor window.
The ? in the SET statements tell the task to pull the values from the Parameter Mapping. So now let's configure the parameter mappings.
In the left pane of the Execute SQL Task Editor, click on Parameter Mapping. If your db connection is OLE or EXCEL, then the Parameter Name will start with 0 and increment by one for each additional parameter. If it's an ODBC connection, you'll start with 1 instead. The parameter names match up with the ordinal position of the ?. So in our example here, #businessunit would be the first parameter mapped and #advisor would be the second. Now you're going to add two parameters. Hit the Add button, then change the Variable Name to your first SSIS variable. Leave Direction set to Input, change Data Type to VARCHAR, set the Parameter Name, then set the Parameter Size to 255. Repeat for the second variable. Your paramter mappings should look something like this:
Make sure you hit OK to save all your changes.
For a script as long as this, one solution that may work for you depending on what you are trying to achieve is to use SSIS script tasks.
Script tasks allow you to use C# (Or Visual Basic) in order to execute SQL via the same System.Data.SqlClient class that you would normally use in other C# programs, such as a console or ASP.NET application.
For your SQL above, put it into a stored procedure, and then execute this stored procedure within the script task. You could then use SqlDataReader or SqlDataAdapter to then read and store the result into a model.
From there, you can choose to manipulate the data within the SSIS script task.
For Example:
SqlConnection connection = new Connection("connection string");
using(SqlCommand command = new SqlCommand("Trans-SQL or stored procedure name", connection)
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(/*Add your parameters...*/);
connection.Open()
SqlDataReader reader = command.ExecuteReader()
while (reader.Read())
{
//Use reader["name"] in here to read values from response into a model
}
}
Is a completely valid way of querying data within a SSIS task. If you would rather not deal with a Reader, you can use the SqlDataAdapter and use the Fill() method to store the result(s) in a dataset.
Overall, when dealing with complex data (and where efficiency isn't too much of a concern), I find that completing actions within SSIS script tasks that get triggered by the control logic is the easier way to use SSIS.
You may find this Integration Services Programming Overview documentation site useful as a reference for some of the things you can do with SSIS script tasks.
On a final note, please be aware that script tasks in SSIS do have some limitations, a key one is that there is generally worse support for newer C# features, that cause issues such as not being able to hit debug breakpoints.

SSRS Conditional default StartDate

I am attempting to set the default start date of a report to the previous business day, which is
dateadd(dd,-1,getdate())
on all days except Monday when it is
dateadd(dd,-3,getdate())
Prior to this report being converted to an SSRS report this was handled in the proc with the query
declare #startDate datetime =
(
select
case
when DATENAME(dw, CONVERT(date, getdate())) = 'Monday' then cast(Convert(date, dateadd(DD,-3,CONVERT(date, getdate()))) as nvarchar(100))
else cast(Convert(date, dateadd(DD,-1,#today)) as nvarchar(100))
end
)
How would I implement this conditional start date using an SSRS =IIF statement?
Thanks
Upon more research I've discovered the method to do this is:
=DateAdd(DateInterval.Day
, Switch(DatePart(DateInterval.WeekDay, Today()) = 2, -3
,DatePart(DateInterval.WeekDay, Today()) = 1, -2
,True, -1)
, Today())
I would use switch personally:
=Switch(
WeekdayName(Weekday(today))="Monday",dateadd(DateInterval.Day,-3,today),
True,dateadd(DateInterval.Day,-1,today)
)

SSRS Report Parameters passed out

I am currently building a number of logging and analysis tools to keep tabs on our SQL environment. We are currently using SQL Server 2014.
What I want to do is keep check of all the parameters that are passed to our reports during the day. All of the reports are currently using stored procedures so in my table or a select statement based on a table is output the stored procedure with the parameters for every time the report was run.
At the end of the day I would then like to be able to take the outputted statement and run it in SSMS without having to use the report. I have been looking at the ExceutionLogStorage table and the ExecutionLog view's and though it has most of the information that I need, the parameters are not in an easily usable state.
Has anyone done something similar to what I have described?
You need to add logging part in your original SP, for example:
Alter procedure a
(#parameter)
As
Begin
..
..
Insert into loggingTable(col)
Values(#parameter)
..
..
End
Then query directly against that loggingTable for getting the history of used parameters
A Google search around this topic quickly brought up the following blog post already identified by the OP as useful and shown below (this query itself is actually an expansion of work linked to by LONG's answer below)
SELECT TOP 1 ParValue
FROM (
SELECT els.TimeEnd
, IIF(CHARINDEX('&' + 'ParameterName' + '=', ParsString) = 0, 'ParameterName',
SUBSTRING(ParsString
, StartIndex
, CHARINDEX('&', ParsString, StartIndex) - StartIndex)) AS ParValue
FROM (SELECT ReportID, TimeEnd
, '&' + CONVERT(VARCHAR(MAX), Parameters) + '&' AS ParsString
, CHARINDEX('&' + 'ParameterName' + '=', '&' + CONVERT(VARCHAR(MAX), Parameters) + '&')
+ LEN('&' + 'ParameterName' + '=') AS StartIndex
FROM ExecutionLogStorage
WHERE UserName='UserName' -- e.g. DOMAIN\Joe_Smith
) AS els
INNER JOIN [Catalog] AS c ON c.ItemID = els.ReportID
WHERE c.Name = 'ReportName'
UNION ALL
SELECT CAST('2000-01-01' AS DateTime), 'ParameterName'
) i
ORDER BY TimeEnd DESC;
Both these approaches though really only give us a starting point since they (variously) rely upon us knowing in advance the report name and parameter names. Whilst we can quickly make a couple of changes to Ken Bowman's work to get it to run against all executions of all reports, we still have the problem that the query hardcodes the parameter name.
The parameters required to execute a report are stored on the Catalog table in the Parameter column. Although the column has a datatype ntext, it is actually storing an XML string. Meaning we can use an XPath query to get at the parameter names
with
CatalogData as (
select ItemID, [Path], [Name], cast(Parameter as xml) 'ParameterXml'
from Catalog
where [Type] = 2),
ReportParameters as (
select ItemID, [Path], [Name], ParameterXml, p.value('Name[1]', 'nvarchar(256)') 'ParameterName'
from CatalogData
cross apply ParameterXml.nodes('/Parameters/Parameter') as Parameters(p))
select *
from ReportParameters;
Executing this query will list all reports on the server and their parameters. Now we just need to combine this with Ken Bowman's query. I've gone with a CTE approach
with
CatalogData as (
select ItemID, [Path], [Name], cast(Parameter as xml) 'ParameterXml'
from Catalog
where [Type] = 2),
ReportParameters as (
select ItemID, [Path], [Name], p.value('Name[1]', 'nvarchar(256)') 'ParameterName'
from CatalogData
cross apply ParameterXml.nodes('/Parameters/Parameter') as Parameters(p))
select
els.TimeEnd
, c.[Name]
, rp.ParameterName
, iif(
charindex(
'&' + rp.ParameterName + '=', ParametersString) = 0
, rp.ParameterName, substring(ParametersString
, StartIndex, charindex('&', ParametersString, StartIndex) - StartIndex
)) 'ParameterValue'
from (
select
ReportID
, TimeEnd
, rp.ParameterName
, '&' + convert(varchar(max), Parameters) + '&' 'ParametersString'
, charindex(
'&' + rp.ParameterName + '=',
'&' + convert(varchar(max), Parameters) + '&'
) + len('&' + rp.ParameterName + '=') 'StartIndex'
from
ExecutionLogStorage
inner join ReportParameters rp on rp.ItemID = ReportID) AS els
inner join [Catalog] c on c.ItemID = els.ReportID
inner join ReportParameters rp on rp.ItemID = c.ItemID and rp.ParameterName = els.ParameterName;
Note that the parameter values are passed to the report as part of a URL, so you'll still need get rid the literal space encoding and so on. Also, this doesn't (yet...) work for multi-value parameters.

shows me long number in float type columns on table

I create a procedure who send me an email, but i get wrong & long numbers in
the columns t, S, Tr. Do i need to casting this columns?
DECLARE #table NVARCHAR(MAX) ;
SET #table =
N'<H1>some Report</H1>' +
N'<table style="width:100%">' +
N'<tr><th>D</th><th>Date</th>' +
N'<th>t</th><th>S</th><th>Tr</th>' +
N'<th>M</th></tr>' +
CAST ((SELECT td=[D],'',td=[D],'',td=round([Tr],0),'',td=round([S],0),'',td=[T],'',td=[M]
FROM [tblDrtrtrttgt]
WHERE [p] > dateadd (dd, -3, getdate())
order BY [S] desc
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;
EXEC msdb.dbo.sp_send_dbmail #recipients='someemail#gmail.com',
#subject = 'EmailofWork',
#body = #table,
#body_format = 'HTML' ;
The number in the table columns:
7.740000000000000e+003 1.525855000000000e+006 8.778700000000000e+004 3.029000000000000e+005
As you thought, casting should help.
Try something like this for your inner SELECT;
SELECT
td=[Description],
'',
td=convert(nvarchar(32), [Date], 102),
'',
td=cast(cast(round([Transactions],0) as int) as nvarchar(32)),
'',
td=cast(cast(round([Sales],0) as int) as nvarchar(32)),
'',
td=[Traffic],
'',
td=[Members]
FROM
[ffb].[dbo].[tblDashboard]
WHERE
[Updated] > dateadd (dd, -3, getdate())
order BY
[Sales] desc
FOR XML
PATH('tr'), TYPE
See the MSDN documentation for Cast and Convert for help on these functions.
Hope this helps.
Rhys

How to replace a date with a standard date in SQL

Ok,
This is a little tricky, I am trying to replace the dates in a SQL Query results with a standard date, based on the month.
For example:
Any dates that are in July get 20140701
August gets 20140801
I could use a case statement:
Case
When Datepart(mm, TxnDate) = 1 and Datepart(yy, TxnDate) = 2014 then TxnDate = 20140101
etc...
but that could get very long as the database goes back 5 years and the result sets cover different periods then.
Any quick suggestions would be greatly appreciated.
Thanks,
declare #mydate datetime
select #mydate = GETDATE()
select cast(datepart(yy,#mydate) as varchar(4)) + RIGHT('0' + RTRIM(MONTH(#mydate)), 2) + '01'
select #mydate = GETDATE() - 10
select cast(datepart(yy,#mydate) as varchar(4)) + RIGHT('0' + RTRIM(MONTH(#mydate)), 2) + '01'
should print 20140701 and 20140601
If you simply want to set every TxnDate to the first of its month, you can do this:
TxnDate = DATEADD(month, DATEDIFF(month, 0, TxnDate), 0)
If your requirement is more complicated than that, you will need to explain.
Try Something like this
SELECT REPLACE (CONVERT(VARCHAR(8), TxnDate, 112),SUBSTRING(CONVERT(VARCHAR(8), TxnDate, 112),7,8),'01') AS [YYYYMMDD]
hope this is what you are looking for