Reporting Services Handscript

SQL Server Reporting Services(简称SSRS),是一个功能强大的报表服务。在MSDN的相关文档以及Google的结果中,可以找到它的一般性描述。在当前SQL Server 2008还在酝酿,2000基本过时的情况下,我们理所当然地讨论其2005版本。

可惜的是,对这项功能的应用,目前似乎仍不广泛,以至于想找一本非常全面而又充满技巧性的教程都如此困难。但好消息是,这是微软开发的产品!秉承微软产品一贯的易上手、帮助翔实的优良传统,对SSRS的探索还是相当值得大书特书的~~~

这一部分主要说说关于SSRS的安装、部署和配置问题。

SSRS的安装

Reporting Services作为SQL Server的一个组件,自然是要伴随SQL Server一起安装了。目前SQL Server的诸多版本,只有Enterprise和Development版本有着对SSRS的完全支持,Standard版本提供了大部分支持,具有高级功能的Express版只支持一些最基本的功能(不含设计器)。因此,在企业部署的时候应该选用Enterprise版,作为开发者应选择Development版。

在安装SQL Server的过程中选中Reporting Services的相关组件,或者更改一个SQL Server的安装以添加SSRS都是可行的。

注意上面说的是服务器端的安装。SQL Server 2005 Development Edition的组件分为服务器和工作站两个部分。在安装完服务器端的相关组件后,还需要在进行开发的机器(可以就在服务器上,也可以是另外的工作站)安装工作站组件。其中的Business Intelligence Development Studio必须安装,这是一个Visual Studio 2005的扩展,如果机器已经安装过VS2005,那它就会直接将BI的开发模板集成进VS中,如果没有装过,那它则会自动替你安装一个VS2005外壳(没有C#、VWD等组件)。

SSRS在服务器端的配置

服务器端配置SSRS有两种方法,一是通过SQL Server Management Studio,登录到Server进行操作;二是通过web访问服务器的Report Manage页面,比如http://IP/Reports。两种方法在功能上略有差别,具体操作过程可以查看相关文档。

这一部分来讨论一下SSRS的一些基本功能,即报表的建立、发布和引用。

创建报表

设计环境

报表设计环境就是那个Business Intelligence Development Studio,以下简称BI。如果项目是在VS2005下进行的,那么就非常方便了,因为可以在一个Solution里像添加普通Project一样来添加BI的工程。事实上我们也是这么做的。

报表创建的基本步骤

在正式开始利用BI开发SSRS之前,强烈建议大家把随机附带的Book Online里的相关教程全部手动完成一遍。

总的来说,一个报表的设计可以归纳为下面的步骤:

  1. 创建报表工程;
  2. 建立数据源(Data Source,rds文件),这是报表与数据库进行通信的桥梁;
  3. 创建数据集,也就是报表的数据来源,报表从数据集获取数据,并不直接访问数据库;
  4. 进行页面布局(layout);
  5. 预览结果(preview),并根据结果进行进一步修改,直到完全满足要求。

在我另一篇日志里有一个简单的例子,来源于SQL Book Online,可以作为一个参考。

报表的发布

设计完报表之后,就要将其发布到Reporting Services服务中,以供调用。我们可以把这个发布称作deploy。

经过实际应用,发现可以有下面三种方法来进行报表的发布

在BI中编译发布

我们设计报表是在BI中进行的,可以利用它来一次性将整个报表工程deploy到服务器上。大致步骤如下:

  1. 菜单执行Project->Properties,将Configuration改为Production,即编辑Production模式的参数;
  2. 在右边分别填入相应的属性值,一般来说TargetDataSourceFolder的内容Data Sources不变,如果数据源有更新,那么就必须将上面的OverwriteDataSources设为True;
  3. 设置TargetReportFolder。这个值是在Report Server中的一个虚拟目录,该工程的所有rdl文件都将存放在这个目录下;
  4. 设置TargetServerUrl。这里就是Reporting Services所在的URL地址,比如本地部署可以用http://localhost/ReportServer。注意后面的那个路径是默认的安装路径,在IIS中打开默认站点后可以看到它,是一个虚拟目录;
  5. 都填写完毕之后,在编译环境中切换编译模式为Deploy,再Start Debugging,这时BI就会自动向Report Server部署这一系列的报表。

完了之后会显示http://localhost/ReportServer这个页面,在这个页面中显示的就是该报表服务器上所有的ReportFolder,而报表则会按照deploy时的设置,分别保存在这些folder内。进入Folder之后,点击报表即可查看,系统已经为我们生成了一个带有ReportViewer的aspx页面。

通过Web下的Report Manager

下面这两种方法均是用来管理报表服务器,发布报表只是它们的一部分功能。

使用Report Manager的大致步骤如下:

  1. 打开Report Manager的页面,一般为http://ServerUrl/Reports;
  2. 进入Data Sources文件夹,上传数据源的rds文件;
  3. 回到根文件夹,建立一个ReportFolder,名称即TargetReportFolder中的值;
  4. 进入该文件夹,把rdl文件逐一上传,它会自动给报表起名,一般接受默认值。

这样就OK了,之后也可以在ReportServer页面下查看内容。

通过SQL Server Management Studio

在SQL Server的配置中,这个工具无疑是最强大的。在登录SSMS的时候,选择Server Type为Reporting Services,然后指定Server的名称,以及登录方式。登录成功后,在Home目录下就是我们在Report Manager中看到的内容,后面的操作大同小异,就不浪费文字了。

利用ReportViewer控件引用报表

建立、发布报表的最终目的还是为了在程序中引用它们,在此我们选择的是最简单的方法——使用ReportViewer控件。

WinForm环境下的ReportViewer

WinForm下的ReportViewer控件,位于Microsoft.Reporting.WinForms命名空间下,在VS2005中默认会出现在ToolBar中,直接将其拖放进窗体即可对其操作。

一般来说,所有报表都必须设置的参数有以下几个:

  • ProcessingMode:这个属性用来设置ReportViewer的数据来源是本地还是远程,在这里我们设为Remote;
  • ServerReport.ReportServerUrl:就是我们前面看到的TargetServerUrl,即报表服务器的URL地址。注意这个地址包含了“ReportServer”,比如http://ServerUrl/ReportServer这样;
  • ServerReport.ReportPath:是ReportFolder和ReportName的组合,比如“/Test/Report1.rdl”,注意注意千万注意,最开始的那个“/”一定不能省略!

对于实际应用,采用代码来控制ReportViewer要比设计时设置属性更加常用,下面就是一个简短的例子,概括了这样一个过程:

在上面的过程中,先是设置ReportPath(ReportServerUrl在本示例中已经指定,实际上应该通过App.config的设置字符串来设置)。然后创建报表参数列表(这个params的名称是在设计报表的时候设置的报表参数,在SQL语句中通过@params进行引用),进而调用ServerReport的SetParameters方法,将参数传递给报表。紧接着,将报表的ShowParameterPrompts属性设为false,即不在ReportViewer的头部显示参数输入提示。最后执行RefreshReport()方法,刷新报表页面。

ASP.NET环境下的ReportViewer

微软的统一性工作无疑是相当出色的,Web下的ReportViewer在使用起来与WinForm下完全相同,唯一不同的就是控件位于Microsoft.Reporting.WebForms下,而诸如ReportParameter等类也改为此命名空间之下。在代码控制报表方面,不需要进行改动即可移植。

Visual WebGUI下的ReportViewer

在项目中,我们是采用VWG来作为程序的框架的。Gizmox开发团队也为ReportViewer设计了相应版本,控件位于Gizmox.WebGUI.Reporting命名空间下,但要注意,它的属性诸如ReportParameter、ProcessingMode等仍然是位于Microsoft.Reporting.WebForms下的,这一点不要搞错。

直接通过ReportServer访问报表

还记得前面提到过的http://ServerUrl/ReportServer吗?SSRS已经为我们准备了一个用来查看报表的方法,即通过URL访问,比如要查看在localhost/ReportServer服务器中,位于Test下的Report1报表,可以直接在浏览器中输入 http://localhost/ReportServer?Test/Report1,SSRS会自动调用一个系统内置的页面来显示它。在这个带参数的URL后面,我们可以通过附加URL参数的方法来对报表进行控制。比如上面的那个例子,在ASP.NET中可以使用Response.Write()向页面写入下面的代码来弹出窗口显示报表:
"<script language=\"JavaScript\"> window.open('http://localhost/ReportServer?Test/Report1&params=" + textQueryString.Text + "&rc:Parameters=false&rs:Command=Render'; </script>"
其中URL参数的构造方法请参阅MSDN相关文档。

上面说的都是常规应用,但实际上一个报表从提出需求到最后部署,绝大部分都不是会了那个示例就能做的,中间会遇到各种各样的问题。在这一部分中,我以问答的形式,将开发过程中遇到的问题以及解决方法分门类地列举出来,并且不断更新。

部署与调试

  • Q:我在ASP.NET下使用ReportViewer载入报表,为什么会出现{用户“NT AUTHORITY\NETWORK SERVICE”授予的权限不足,无法执行此操作。 (rsAccessDenied)}的错误?
    A:这是由于IIS下ReportServer虚拟目录的访问权限没有设置正确。解决问题的方法有三种:

    • 在服务器端访问http://localhost/Reports,进入Report Manager,然后点击“属性”标签页下的“新建角色分配”,在“组或用户名”中填入“NT AUTHORITY\NETWORK SERVICE”(没有两边的引号),在下面勾选Browser,确定。这是给该账户赋以浏览报表的权限,我强烈推荐这种方法;
    • 在IIS中,修改默认站点下ReportServer虚拟目录的属性,在Directory Security选项卡中,点击Authentication and access control中的Edit,开启匿名访问,将匿名访问帐户设为管理员账号,本地登录的就设为Administrator,域账号登录的就设为具有管理员权限的域账号。这样可以使访问ReportServer的连接以管理员权限浏览报表。这也是网上流传最广的方法,但存在严重安全隐患,开发调试的时候没问题,真正部署的时候不建议使用;
    • 专门为Reporting Services建立一个匿名帐户,比如IUSR_ReportView,然后在Report Manager里分配Browser角色,还有等等后续步骤。这是最麻烦的,步骤之多我都懒得在这里写全,同样在网上流传很广,但我觉得只有实在闲着没事干的人才会用。。。
  • Q:我在Visual Studio里开发VWG,以debug方式运行,然后在ReportViewer导出PDF时就报Session Expired错误,这是怎么回事?
    A:其实我也不知道为什么。。。解决的方法是不用debug方式,直接在浏览器访问站点,就OK了。至于其原因,呼唤高人来解释~~~

报表数据相关

  • Q:我现在不仅仅想向报表传递传统的SQL参数,比如@ID、@Count,而是想整条WHERE子句以至整个SQL语句的任何地方都可以用参数的形式来控制,可以吗?
    A:当然可以,这都不行那SSRS也太圡了。。在这里需要用到报表语句。用过Excel吧,单元格的值如果用“=”开头,那后面就可以跟表达式,报表语句也一样。一个最简单的例子,比如像我现在想用参数传递一整条WHERE子句,就这么做:

    1. 菜单中Report->Report Parameters,Add一个新参数,假定Name叫做WhereString,类型String,别的不动
    2. 在Data页中修改需要接受参数的DataSet,假设原来SQL语句的内容为“select * from table1 where age between 10 and 15 and id>40”
    3. 修改为="select * from table1 where " + Parameters!WhereString.Value
    4. 好,切换到Preview中,看结果吧。

    注意这里的where后面有个空格,尤其是在构造SQL语句的时候,一定要特别注意空格的使用。

  • Q:我在那个Parameters提示框中什么都没填,直接点击View Report,出错了耶。。。
    A:-_-|| 当然会出错,SQL语句中的where后面没有条件,语法不正确啊。。像这种情况,你得在表达式语句里做一个判断,看是否传入的参数为空。上面那个例子,就可以改为:=”select * from table1″ + IIF(Parameters!WhereString.Value<>””, ” where ” + Parameters!WhereString.Value, “”)这里的IIF是报表语句的一种,属于Program Flow语句。至于更博大精深的用法,参阅文档~~
  • Q:这太神奇了,那你能告诉我,如果我想在一个页面里加入“第X页/共Y页”这种,又该怎么做呢?
    A:这还是要用到报表语句。进入Layout视图,在任意一个文本框右键点击然后选Expression,就是前面有个“fx”图标的那个,就能看到表达式编辑器。在左下的那个框 中列出的就是报表语句的类别,看到Globals了吗?点击一下,右边就会有一些关于报表本身的常量,那个PageNumber和TotalPages就是这里要用的。前面用到的Parameters和 IIF在这里也都能找到。灵活应用这些元素可以极大丰富报表的表现力。哦,忘了说一点,PageNumber和TotalPages这两个量都只能在页眉或者页脚处才可使用,所以在用它们之前需要在Layout视图中,菜单Report->Page Header(或Page Footer),开启 页眉或页脚,然后在里面引用。

报表Layout相关

  • Q:为什么我的报表打印出来之后水平方向跨页啦?我在设计页面中明明没有越界啊!
    A:cft…你的眼睛欺骗了你。设计界面的那个页面边界其实跟你的纸张页面完全没有关系,SSRS也没有提供整页居中的功能,所以你必须一点点地微调你的页面布局。首先我建议在菜单Report->Report Properties->Layout选项卡中,将左右Margin都改为0。然后回到设计界面,通过手动指定控件的Locate属性的方法,来确定左侧边界的大小。比如现在的纸张是A4大小(21cm*29.7cm),我的正文表格总宽度设置为17.75cm,剩下的3.25cm是左右页边距总和,按理说应该各分配1.625cm,但考虑到表格里的表格线也是有宽度的(我设的是1pt),因此将左页边距设为1.6cm,也就是把控件摆放在距离设计页面左侧1.6cm的位置,再说的明白点就是把靠左的各控件的Locate属性中的Left元素的值设为1.6cm(好多定语啊。。我不是故意的。。)。进行预览的时候建议用ReportViewer的导出功能导出为pdf查看,也可以打印到pdf、xps,要是你再土豪一点,直接打印到纸上看是最好。这个微调是个痛苦的过程。

经过这一段时间的开发经历,个人感觉SSRS还是非常好用的,与SQL Server的无缝集成,layout的灵活多变以及报表语言的强大功能,加上微软产品的亲和性,带来的是清爽的使用体验。不过SSRS的执行效率并不高,尤其是SQL 2005版的SSRS在建立DataSet的时候还只能用SQL语句来查询,实现复杂的业务逻辑还不是很方便。并且在动态列显示以及动态页面设置还有待提高。期待SQL Server 2008版SSRS能够更上一层楼~~