Category Archives: SSRS

exorcising ghosts

ERROR: THROWING MICROSOFT.REPORTINGSERVICES.DIAGNOSTICS.UTILITIES.REPORTSERVERSTORAGEEXCEPTION: , AN ERROR OCCURRED WITHIN THE REPORT SERVER DATABASE. THIS MAY BE DUE TO A CONNECTION FAILURE, TIMEOUT OR LOW DISK CONDITION WITHIN THE DATABASE.;

Subscriptions failing. Cryptic messages. “Failure sending mail:Failure sending mail”. Time to check out the logs. I’m running SQL Server 2016.

In SQL Server Reporting Services 2016 or earlier: C:\Program Files\Microsoft SQL Server\MSRS13.MSSQLSERVER\Reporting Services\LogFiles

Where to start…

Do I look at permissions? Service Accounts? Network conditions? Disk Space/Queue Length?

This was it. This was the error filling up our SSRS logs at a rate of over 9,000 entries/second, 32 MB log files produced every minute, for the last 4 1/2 days. 483 GB in all. Storage volume was 1.10 TB free of 1.72 TB so I could breathe a little easier. CPU was not spiked and memory allocations were optimal. No authentication issues present, and network connectivity was strong. What was happening he pondered?

SQL Server Profiler, you wonderful tool, to the rescue. I began a trace and found the gremlin instantly:

exec msdb.dbo.sp_delete_job @job_name=N'72383D9B-8662-4973-B71F-402DFAC50F1C'
go
exec msdb.dbo.sp_delete_job @job_name=N'72383D9B-8662-4973-B71F-402DFAC50F1C'
go
exec msdb.dbo.sp_delete_job @job_name=N'72383D9B-8662-4973-B71F-402DFAC50F1C'
go
exec msdb.dbo.sp_delete_job @job_name=N'72383D9B-8662-4973-B71F-402DFAC50F1C'
go
exec msdb.dbo.sp_delete_job @job_name=N'72383D9B-8662-4973-B71F-402DFAC50F1C'
go

This is what happens when your server attempts to delete a ghost, a job that has passed and is no longer with us. The resolution was quite simple – bring the job back to life. Create a new job with the same name, purpose unimportant. Within a millisecond the job will be terminated. We mourn the loss, all except the log files which take a much needed rest.

Happy Troubleshooting!

Page footer displays in preview but not when printing

I added a text box to a report’s page footer which featured the execution team and user id.  No problem there.  I previewed the report and all looked well, but when printing the page footer did not show up.  Page footers do have properties of “PrintOnFirstPage” and “PrintOnLastPage”, but both of these were set to True so this wasn’t my issue.  I threw a line into the footer and previewed again, and in print preview the line did show but the text box was still missing.  Back at the report, I increased the size of the footer so that the box had plenty of room all around it, and what do you know, it then showed on the print preview.  I’m guessing that there may have been some time of overlap or other issue going on, even though I didn’t see any warning in Output.  I tweaked the box size and placement again, and re-sized the footer to the original specs and all was still well.  Still not sure what the issue was but playing around with the text element was the fix in this case.

Happy Reporting!

Talking about Installing 32-bit ODBC Drivers on Windows 7

 I had to create a report today that used information from two different data sources, the first was SQL Server, and the second was an Access database.  I needed to create an ODBC connection to the Access database first so that I could query the data in my report.  I am running Windows 7 64 bit, and from prevous experience I know that I should be creating a 32 bit ODBC connection and that Windows provides both a 64 bit and 32 bit ODBC manager.  I opened up my System32 folder and found the 32 bit ODBC executable, odbcad32.exe and launched it.  Much to my suprise, there was no Access driver listed in the manager.  I did some quick searching and came across this incredibly helpful article.  The article explains that the odbcad32.exe that exists in the System32 folder is in actuality the 64 bit ODBC manager, and that both the 32 bit and 64 bit ODBC managers exist in the 64 bit system directory, SysWOW64, with the 32 bit manager having the same name (odbcad32.exe) as the 64 bit in the 32 bit directory (is that enough bits yet?).  Once I found the proper manager, I was able to add my DSN and get the report running. 

On a side note: this issue came about after having solved another cool problem, which was using data from one dataset into another.  I’ll create another entry to describe that process and solution.

Hope this helps.  Happy Reporting!

Changing Subscription Owner

Our report administrator was looking over some productivity reports that had been scheduled to be emailed to selected managers using the report server subscription option.  He had found that the reports had not been emailed in quite some time (although the managers that were supposed to receive the message never notified us!) and were failing with a message that the subscription owner does not exist.  The subscriptions had been created by our former report administrator and whose domain account had been removed.  Without the active domain account, every subscription created under that user was failing.  I submitted as a fix to create a new domain user that would never have to be removed and re-create the subscriptions when logged in under the new account.  This however did not fix the problem, as the subscription owner is tied to the owner of the report. Using this method, each report would have to be re-created using the new account.  I performed a quick search and came up with this blog which featured the solution.  The fix was to update the owner of the subscriptions directly in the subscriptions table in the report server database.  I ran the change using the example on that blog and update the owner.  We fired off a new subscription on one of the reports and it sent out perfectly. 
 
After this, I started poking around in the report server database, which I have unfortunatley not looked at much in the past. I created a quick query to bring back all of the current subscriptions, their owners, the report they were running under, and what the results of the subscriptions are.  Using this I can now at a glance check the status of all our subscriptions and look for failures and other issues.  Here’s the query I used:
 

SELECT

u.UserName, u.UserType, c.Path, c.Description, c.creationDate, c.ModifiedDate, s.modifiedDate, s.Description, s.LastStatus, s.LastRunTime

FROM Subscriptions s

INNER

JOIN Users u

ON

s.ownerid = u.userid

INNER

JOIN Catalog c

ON

s.report_OID = c.ItemID

ORDER

BY u.Username, s.LastRunTime DESC

 
Hope this helps.  Happy reporting!

Hiding fields using Multi-Value parameters

I have a report where I switched all the single valued parameters to multi-value.  The report had 8 sections whose visibility was controlled through the selection of a parameter.  The user could choose one of the sections or all.  I had set the sections up as rows of a table and used the following expression on the hidden attribute for that table row: IIF(Parameters!<parameterName>.Value = <thisSectionName> OR Parameters!<parameterName>.Value = "ALL", false, true).  This expression would cause this section to only be displayed if that section’s name or All was picked from the parameter ("ALL" was a static value I added to the parameter value when it was created).  However this no longer worked when switching to multi-value parameters.  The solution was to combine the JOIN() function, which creates a delimited string out of its argument, with the InStr() function, which returns the starting position of a string within another string.  Combining the two resulted in the following expression: IIF(InStr(JOIN(Parameters!<parameterName>.Value), "<thisSectionName>") > 0 OR Parameters!<parameterName>.Count = <totalNumberOfParameterValues>, false, true).  This expression will create a string containing all of the selected values of the multi-value parameter and search it for an occurence of the section name. If found, the integer position will be returned. If that value is greater than 0, then we want the section displayed (hidden = false).  Also, the expression checks to see if all of the values are selected, which is controlled by the count property of the parameter compared against the total number of possible values, which again will signal that we want the section displayed.  If the string is not found or all of the values are not selected, then the section will not be displayed (hidden = true).
 
Hope this helps.  Happy Coding!

Displaying the value of a Multi-Value parameter

I was working on re-designing a report today where I was changing certain single-valued parameters to multi-value.  I love this ability in that it allows the user to create much more dynamic reports.  The previous version of the report was displaying the value of the selected parameters in text boxes in the header of the report using the expression: ="<parameterName>: " & Parameter!<parameterName>.Label.  Unfortunatley, this caused an error when switching to multi-value parameters.  I found a couple of great articles and comments that showed how to display the value / label of a multi value parameter (links below).  You can use the JOIN(expression, delimiter) function to create a delmited string of either the parameter’s values or labels. To make a comma delimited list of the parameter’s labels, you would use the expression: JOIN(Parameters!<parameterName>.Label, ",").  This solution works perfectly. I still had one other problem.  One of my parameters contained a large list of staff, and I didn’t want every  staff member to be shown if the user selected all of the values for the parameter.  Fortunately, SSRS report parameters have an attribute called Count that contains the number of selected values. With this, you can construct a conditional expression to control what is displayed depending on how many values are selected.  For example, This expression will only display the word "All" if all of the values have been selected, or else it will display the comma delimited list of values: IIF(Parameters!<parameterName>.Count = <totalNumberOfValues>, "All", JOIN(Parameters!<parameterName>.Label, ",")).  So how do you determine the total number of values to compare against? If you have a non-queried dataset for a parameter, then the solution is easy; simply count up the values you have and that’s your number.  For my purposes, I was gathering a list of staff which can change over time.  The solution was to create a new dataset that returned the count of staff, using the same query that retrieved the staff names for the parameter.  Once I had the count, I created a new internal parameter and assigned it’s default value to the value of that count.  Now in my expression, I can compare the count of parameter values to the count of staff retrieved and contained in my internal parameter.  This way the results will always be the same and dynamic. 
 
Hope this helps. Happy coding!
 

Parameter Ordering – Forward dependencies are not valid.

We have a report at work that displays staff payroll information.  The report is viewed by managers and executives.  Each person viewing the report only has access to certain departments (one or more) that we control through a table we built.  The viewer is presented with a list of departments to choose from, and their choice of department is validated in our table using the Global report value UserID.  They will see the information if authorized, or otherwise a message displays stating as such. As this report was written by someone else no longer working at the company, my question was why are we even offering a list of all departments if the viewer can only select specific ones?  The solution was to list only those departments for which the viewer could access in the report parameter.  To do this, I created an internal report parameter that got the network id of the current viewer using the Global UserId value, then used that parameter to query the authorization table for those departments that the viewer was assigned.  Sounded fine, except when running the report I received an error stating that "Forward dependencies are not valid."  A quick Google later (can I use that as a unit of time?)  and I found a forum entry on one of my favorite SQL sites, SQL Server Central (registration required).  The entry mentioned that the ordering of report parameters in the paramter dialog matters.  It makes total sense, but not something you would commonly think about.  I moved the user id parameter above the parameter that uses it to get the list of departments, and the report displayed as expected.     
 
Hope this info helps.  Happy Reporting!