Monday, July 11, 2016

SSRS: Download all report RDL files with folder specific from Report Server in single shot

SSRS Report Server does not provides visual option to download all reports at single shot. Report Manager does not support downloading all the report files (.rdl files)  at single shot.That is why we have to face crucial situation while migrate report server to higher version. 

They provided solution for that. By the help of Bulk Copy (BCP) we can able to achieve it.
For that we have to write few lines of SQL code.

Today we will achieve the same by BCP option.

To do that first we have to know some basic about report database. When we configure Reporting Services configuration manager then we have to create report database. This report database contain whole information about reports. If we connect this report server database to SSMS, we can see various tables inside it.





Here one of the most important table is dbo.Catalog. This table contain report information and report XML body. Below picture showing few column of dbo.Catalog.



Type is the one column of  dbo.Catalog Table. Here we can see some number, each number has a specific indication. 

1 = Folder
2 = Report
3 = Resources
4 = Linked Report
5 = Data Source
6 = Report Model
7 = Report Part

8 = Shared 

To get all the report we have to pass type as 2.

Below is the SQL scripts to download all report RDL files


DECLARE @ReportDetails TABLE
(
  Report_No int,
  ItemId uniqueidentifier,
  Report_name nvarchar(425),
  Report_Path nvarchar(425),
  Folder_Path nvarchar(425)
)

DECLARE @intFlag INT=/*To start with 1 in while loop*/
DECLARE @MaxReportCount INT

Insert into @ReportDetails(Report_No,ItemId,Report_name,Report_Path,Folder_Path)
select ROW_NUMBER() over (order by ItemId) as Report_No,ItemId,Name,[Path],replace(SUBSTRING(PATH,1,LEN(PATH)-(LEN(Name)+1)),'/','\') as Folder_Path
from [dbo].[Catalog]
   where [Type]=2 /*Load all the reports (Type=2 indicates) from catalog table to table variable*/
select @MaxReportCount = MAX(Report_No) from @ReportDetails /*Get max count to pass as highest value in while loop*/


WHILE (@intFlag <= @MaxReportCount)  /*Declare loop to generate rdl file of all reports one by one*/
BEGIN
     Declare @FolderContainer AS NVARCHAR(200)
     declare @cmd as varchar(MAX) /*Hold xml file for report*/
     declare @Reportqueryout as varchar (240) /*Hold report output path*/
     declare @DynamicQuery AS NVARCHAR(MAX) /*Hold xp_cmdshell string for           generating RDL file*/

     Select @FolderContainer='D:\ReportDetails'+Folder_Path from @ReportDetails where Report_No=@intFlag

     Select @cmd =  CONVERT(VARCHAR(MAX),  
           CASE       
             WHEN LEFT(C.Content,3) = 0xEFBBBF THEN STUFF(C.Content,1,3,'''')        
             ELSE C.Content        END) 
     FROM  [ReportServerPDReport].[dbo].[Catalog] CL
       CROSS APPLY (SELECT CONVERT(VARBINARY(MAX),CL.Content) Content)WHERE  CL.ItemID =
               (Select ItemId from @ReportDetails
     where Report_No=@intFlag)

     select * into ##Temp from (select @cmd temp) a /*store XML file to temp table*/
       ------------------------------------
      
        EXEC master.dbo.xp_create_subdir @FolderContainer
   
       ------------------------------------
        select @Reportqueryout='"'+@FolderContainer+'\'+Report_name+'.rdl"'
     from @ReportDetails
     where  Report_No=@intFlag /*Generate output path */

     select @DynamicQuery='EXEC master..xp_cmdshell ''bcp " '
                           + 'Select Temp from ##Temp" QUERYOUT '
                           + @Reportqueryout
                           + ' -c -S Localhost\reportinstance  -T''' /* Here Localhost\reportinstance  is the SQL server name with instance*/

     EXEC SP_EXECUTESQL @DynamicQuery
           
     Drop table ##Temp

     SET @intFlag = @intFlag + 1 /*By increasing this go to or fetch next report*/



END

Steps to understand this

1. Open ReportServer database in SSMS (SQL Server management Studio).
2. Select all data from dbo.catalog table where type=2 (2 indicates reports only)
3. Create table variable named @ReportDetails to store few columns form dbo.catalog              table.
4. Create 2 more variable named @intFlag and @MaxReportCount, next assign values.
5. Run while loop from 1 to @MaxReportCount, and convert content to XML file.
6. Push the XML file to ##Temp table.
7. Give path for export RDL file.
8. Create proper syntax of xp_cmdshell and store it into @DynamicQuery variable.
9. Now execute the @DynamicQuery variable.


In case of more than 500 reports in report server, we can use one more way to avoid System.OutOfMemoryException" exception



DECLARE @intFlag INT=/*To start with 1 in while loop*/
DECLARE @MaxReportCount INT

Select ROW_NUMBER() over (order by ItemId) as Report_No,ItemId,Name as Report_name,[Path] as Report_Path,replace(SUBSTRING(PATH,1,LEN(PATH)-(LEN(Name)+1)),'/','\') as Folder_Path
       into #ReportDetails
       from [dbo].[Catalog]
       where [Type]=2 /*Load all the reports (Type=2 indicates) from catalog table to table variable*/
select @MaxReportCount = MAX(Report_No) from #ReportDetails /*Get max count to pass as highest value in while loop*/

     Declare @FolderContainer AS NVARCHAR(200)
     declare @cmd as varchar(MAX) /*Hold xml file for report*/
     declare @Reportqueryout as varchar (240) /*Hold report output path*/
     declare @DynamicQuery AS NVARCHAR(MAX) /*Hold xp_cmdshell string for generating RDL file*/

WHILE (@intFlag <= @MaxReportCount)  /*Declare loop to generate rdl file of all reports one by one*/
BEGIN
    
     Select @FolderContainer='D:\ReportDetails'+Folder_Path from #ReportDetails where Report_No=@intFlag

     Select @cmd =  CONVERT(VARCHAR(MAX),  
           CASE       
             WHEN LEFT(C.Content,3) = 0xEFBBBF THEN STUFF(C.Content,1,3,'''')        
             ELSE C.Content        END) 
     FROM  [ReportServerPDReport].[dbo].[Catalog] CL
       CROSS APPLY (SELECT CONVERT(VARBINARY(MAX),CL.Content) Content)WHERE  CL.ItemID =
               (Select ItemId from #ReportDetails
     where Report_No=@intFlag)

     select * into #Temp from (select @cmd temp) a /*store XML file to temp table*/
       ------------------------------------
      
        EXEC master.dbo.xp_create_subdir @FolderContainer
   
       ------------------------------------
        select @Reportqueryout= '"'+@FolderContainer+'\'+Report_name+'.rdl"'
     from #ReportDetails
     where  Report_No=@intFlag /*Generate output path */

     select @DynamicQuery='EXEC master..xp_cmdshell ''bcp " '
                           + 'Select Temp from #Temp" QUERYOUT '
                           + @Reportqueryout
                           + ' -c -S Localhost\reportinstance  -T''' /* Here Localhost\reportinstance  is the SQL server name with instance*/

     EXEC SP_EXECUTESQL @DynamicQuery
           
     Drop table #Temp
        set @FolderContainer=''
        set @cmd=''
        set @Reportqueryout=''
        set @DynamicQuery=''

     SET @intFlag = @intFlag + 1 /*By increasing this go to or fetch next report*/
      

END

No comments:

Post a Comment