SSRS 报表中有一些高级的技巧,平常很少用到,下面我通过这个案例来展现一下如何在实际开发中使用它们,并且如何解决一些实际的需求。

这张报表分别统计了不同的 Product 产品在不同的月份的 Order 订单数量, Due 付款数量和 Ship 装船数量。

Start Date 和 End Date 的时间范围作为筛选,很显然第一个 Matrix 是以 Order Date 作为比较条件,第二个是以 Due Date, 第三是以 Ship Date 作为比较条件。

现在需要变成这样的一种需求 - 在一个 Matrix 中来展现按月分组之后的 Order Count, Due Count, Ship Count。

这个变化复杂在什么地方?

第一 ,无法确定到底是按照 Order Date, Due Date 还是 Ship Date 作为列的父分组,如果按照 Order Date 分组,那么 Due Count 和 Ship Count 下的数据又该如何统计。很显然订单日期在 2007年7月份的这笔订单,它的 Due Date 有可能落在 2007年8月份,它的 Ship Date 有可能落在 2007年9月。但是在一个 Dataset 中只能要么按照 Order Date,要么按照 Due Date 或者 Ship Date 来过滤。因此既不能按照 Order Date,也不能按照 Due Date 或者 Ship Date 来作为查询的 WHERE 条件。

第二,在月份的分组之下没有条件能够判断那些数据是属于 Order Count, Due Count 和 Ship Count。月份之下的分组没有依据,无法分组。

当然解决以上两个问题在 SQL 查询中是比较容易解决的,就是通过硬编码将三个查询出来的 Dataset 合并成一个更大的 Dataset 并设置列标识。

但是现在的问题是,这三个 Dataset 已经都存在了,并且我们假设是没有办法改变的情况下如何解决这个问题,比如数据源使用的是无法通过 SQL 查询的 Report Model 的 Entity。

三个 Dataset 的示例查询语句,可以自行替换日期参数。

USE AdventureWorksDW2008R2
GO SELECT DP.EnglishProductName,
F.SalesOrderNumber,
DD.FullDateAlternateKey AS 'OrderDate'FROM dbo.FactInternetSales AS F
INNER JOIN dbo.DimProduct AS DP
ON F.ProductKey = DP.ProductKey
INNER JOIN dbo.DimDate AS DD
ON F.OrderDateKey = DD.DateKey
WHERE DD.FullDateAlternateKey BETWEEN '2007-01-01' AND '2007-09-30'AND DP.EnglishProductName IN ('Adjustable Race',
'All-Purpose Bike Stand',
'AWC Logo Cap',
'BB Ball Bearing',
'Bearing Ball') SELECT DP.EnglishProductName,
F.SalesOrderNumber,
DD.FullDateAlternateKey AS 'DueDate'FROM dbo.FactInternetSales AS F
INNER JOIN dbo.DimProduct AS DP
ON F.ProductKey = DP.ProductKey
INNER JOIN dbo.DimDate AS DD
ON F.DueDateKey = DD.DateKey
WHERE DD.FullDateAlternateKey BETWEEN '2007-01-01' AND '2007-09-30'AND DP.EnglishProductName IN ('Adjustable Race',
'All-Purpose Bike Stand',
'AWC Logo Cap',
'BB Ball Bearing',
'Bearing Ball') SELECT DP.EnglishProductName,
F.SalesOrderNumber,
DD.FullDateAlternateKey AS 'ShipDate'FROM dbo.FactInternetSales AS F
INNER JOIN dbo.DimProduct AS DP
ON F.ProductKey = DP.ProductKey
INNER JOIN dbo.DimDate AS DD
ON F.ShipDateKey = DD.DateKey
WHERE DD.FullDateAlternateKey BETWEEN '2007-01-01' AND '2007-09-30'AND DP.EnglishProductName IN ('Adjustable Race',
'All-Purpose Bike Stand',
'AWC Logo Cap',
'BB Ball Bearing',
'Bearing Ball')

新建一个报表,并拖放一个 Matrix,并预先只选择包含有订单的 Dataset,行以 English Product Name 来分组,列暂时不动。

在 Column Group 右键选择添加一个分组,暂时按照 OrderDate 分组,不要选择 ‘Add Group header’。

这样一来 ColumnGroup 之上就有一个 OrderDate 的分组了,继续选择 ColumnGroup 并选择添加 Adjacent After。

Adjacent Group - 相邻的分组,这样在 OrderDate 父分类下就可以创建一个或者多个并列的子分组了。

ColumnGroup 是以 Order Date 作为分组的依据的,这里为它添加两个同样以 Order Date 分组的相邻分组。

要注意这个分组的括号的变化,与直接在子分组下邮件添加新列是有区别的。

将所有按照 OrderDate 分组的条件格式化,因为 Order Date 本身是类似于年-月-日结构的,但是我们分组的条件是基于年-月级别。

只有按照这种分组方式,才可以将第二个相邻分组和第三个相邻分组的列名更改掉。

因为上面分组的条件是按照 yyyy-MM 格式化的,为了后面条件对比的统一性,为每一个 Dataset 添加一个 KEY,也按照这个格式格式化。

添加了 OrderMonthKey, DueMonthKey 和 ShipMonthKey。

在第二个相邻和第三个相邻分组的聚合数据处要实现这样的逻辑:

由于父分组都是按照 Order Date 来分组的,并且所有三个子分组也都是按照 Order Date 来分组的,所以如果按照第一个子分组下的 Count(SalesOrderNumber) 复制到第二个或者第三个子分组的话,结果应该是一样的。

这样就先解决了第一个分组的问题。

第二就是继续以 OrderDate 作为查找条件,去查找有哪些 Due Date 和 Ship Date 在同一个月的 SalesOrderLineNumber。

因此在第二个子分组中,计算在这个月中的 Due Count 就是如下逻辑 -

通过当前 Order Month,到 DS_DUE Dataset 中去比较有哪些 Due Month 和 Order Month 是一样的,于是把查询到的 SalesOrderNumber 全部返回回来。最后通过 .Length 来获取返回的 SalesOrderNumber 数量。

这个逻辑也用到 Ship 分组统计上。

再来比较一下之前的报表

和更改之后的报表 - 修改之后的报表出现了问题。所有产品的 Due Count 和 Ship Count 都是一样的,结果不正确。

错误的原因是什么 ? 因为在 Lookup 查找的时候没有考虑行分组的问题,也就是说 Lookup 的时候只考虑了比较月份,而没有考虑要同时比较产品和月份,即不同的产品下,不同月份下的 Sales Order Count。

引申了一个新的技巧 - 如何在 LookupSet 的时候比较多个列 ? 其实很简单,拼接字符串即可。

保存并查看报表,这次就都正确了。

上面的这些报表处理技巧在实际开发过程中非常实用,可以在不更改原有 Dataset 和查询结构的情况下很容易的实现了新的需求。

关于 LookupSet 的使用可以参考 MSDN LookupSet,同时 Lookup 函数也是非常常用的,不同的是 Lookup 是返回一对一的结果,而 LookupSet 是一对多的结果。


更多 BI 文章请参看 BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)

如果觉得这篇文章看了对您有帮助,请帮助推荐,以方便他人在 BIWORK 博客推荐栏中快速看到这些文章。


微软BI 之SSRS 系列 - 使用 LookupSet 和 Adjacent Group 等高级技巧在报表中跨 Dataset 分组查询的更多相关文章

  1. 微软BI 之SSRS 系列 - 基于时间段参数的 MDX 查询以及时间日历 Date Picker 的时间类型参数化

    今天在天善问答里看到一个问题,如果我没有理解错的话,它应该是指比如在一个报表中选取一个时间段,然后求出这个时间段的某个 Measure 的 SUM 和.并且同时求出这两个时间点对应的上一年的时间点之间 ...

  2. 微软BI 之SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表

    基于数据仓库上的 SSRS 报表展示,一般可以直接通过 SQL 查询,存储过程,视图或者表等多种方式将数据加载并呈现在报表中.但是如果是基于 Cube 多维数据集的数据查询,就不能再使用 SQL 的语 ...

  3. 微软BI 之SSRS 系列 - 在 Cube 中通过 MDX 查询实现基于父子递归关系的汇总报表

    之前我写了一篇在 SSRS 开发中处理这种父子关系的汇总与聚合的文章 (SSRS 系列 - 使用分组 Group 属性实现基于父子递归关系的汇总报表),示例中的查询是基于 SQL Server 关系型 ...

  4. 微软BI 之SSRS 系列 - 实现 Excel 中图表结合的报表设计

    来自群里面讨论的一个问题,EXCEL 中有类似于这样的图形,上面是 Chart, Chart X轴上的值正好就是下方 Table 的列头,这个在 SSRS 中应该如何实现?   SSRS 2008.2 ...

  5. 微软BI 之SSRS 系列 - 报表邮件订阅中 SMTP 服务器匿名访问与 Windows验证, 以及如何成功订阅报表的实例

    这篇文章源于在上一篇博文中有园友提出订阅 SSRS 报表时的一个问题,  于是就好好总结了一下,把有关 SSRS 报表订阅的要点和容易出现问题的地方写出来,希望对大家有所帮助! 参看上一篇博文 - S ...

  6. 微软BI 之SSRS 系列 - 如何实现报表导航 Navigation 和钻取 Drill Down 的效果

    开篇介绍 如何在 SSRS 报表中实现标签导航 Navigation 和向下钻取 Drill Down的效果? 如同下面这个例子一样 - 在页面第一次加载的时候,默认显示是全部地区的销售总和情况,上面 ...

  7. 微软BI 之SSRS 系列 - 巧用 RunningValue 函数在分组中排序并设置 RANK 排名

    开篇介绍 经常有像类似于这样的排序需求,以及设置分组下的排序序号.比如此图中要求城市 City 在省份下按照 Internet Sales Amount 总销售额进行排序,并标识在各省份下的排名. 实 ...

  8. 微软BI 之SSRS 系列 - 如何设置页标题重复

    开篇介绍 这个问题大家经常碰到,特意写一下如何解决这个小问题. 问题 默认情况下当报表超过一定的高度会自动分成多页. 第二页默认是看不到标题的. 解决方法 2012版本下在 Column Groups ...

  9. 微软BI 之SSRS 系列 - 如何在 MDX 查询中获取有效的 MEMBER 成员属性作为参数传递

    这篇小文章的来源是 天善问答,比如在报表中要根据点击某一个成员名称然后作为参数传递给自身报表或者下一张报表,这个在普通的 SQL 查询中没有任何问题.但是在 MDX 中查询是有区别的,比如在 MDX ...

随机推荐

  1. 使用 MVVMLight 绑定数据(转)

    MVVMLight绑定数据示例 好了,我们在新建了两个项目,分别是“MVVMLight的主程序” 与  “Model层”,运行的效果及解决方案结构如下: 其实很简单,就是绑定了一个数据源而已,编写的代 ...

  2. C# CSGL

    转.修改自ShareIdeas文章C# 基于CSGL opengl OpenGL是一个功能强大的开放图形库(Open Graphics Library).其前身是SGI公司为其图形工作站开发的IRIS ...

  3. Facebook工程师是如何改进他们Android客户端的

    from://http://greenrobot.me/devnews/facebook-engineer-improve-android-app/ Facebook工程师是如何改进他们Android ...

  4. Oracle 备份、恢复单表或多表数据步骤

    Oracle 备份.恢复单表或多表数据步骤,适用于 Oracle 8.9.10.        *备份单表或多表数据: exp user/password@server file=filefullpa ...

  5. 详解Java Spring各种依赖注入注解的区别

    注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired.Resource.Qualifier.Service.Controller.Repository.Comp ...

  6. SQL:获取中文周几

    ) = case DatePart(DW, GetDate()) then '周日' then '周一' then '周二' then '周三' then '周四' then '周五' then '周 ...

  7. Linux学习15-CentOS安装mysql5.6环境

    前言 在linux上安装mysql5.6版本,并远程连接mysql数据库操作 安装mysql mysql的安装可以用yum安装更方便 [root@yoyo ~]# cd /usr/local/ [ro ...

  8. 每天一个linux命令-用户之间切换

    怎么从root用户切换到普通用户 su是在用户间切换,可以是从普通用户切换到root用户,也可以是从root用户切换到普通用户.如果当前是root用户,那么切换成普通用户test用以下命令:su - ...

  9. 关闭Windows Server 2012的IE增强安全配置

    在Windows Server 2012中,IE的安全性被增强,对于没有加入信任站点的网址会弹出提示框: 微软这样做是为了增强IE的安全性,但是在实际的使用过程中并不是很方便.如果是个人电脑安装了Wi ...

  10. 解决Using 1.7 requires compiling with Android 4.4 (KitKat); currently using API 4

    有时候我们可能需要将项目的版本降低,比如4.4降低到2.2这样的,可能会遇到类似于这样的错误 Using 1.7 requires compiling with Android 4.4 (KitKat ...