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

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

2013-10-09 23:09 by BI Work, 184 阅读, 0 评论,收藏编辑

基于数据仓库上的 SSRS 报表展示,一般可以直接通过 SQL 查询,存储过程,视图或者表等多种方式将数据加载并呈现在报表中。但是如果是基于 Cube 多维数据集的数据查询,就不能再使用 SQL 的语法了而应该使用 MDX 查询。关于 MDX 和其它 SSRS 的文章,请参看 BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)

这是我们要实现的报表效果,使用的数据库示例是 MDX Step by Step 2008 的 SSAS DEMO 数据库。

收起的效果 - 按 Product Category 分组聚合并呈现所有财年的销售情况。

展开之后能够看到 Product Sub Category 的销售数据。

通俗一点的讲,从数据仓库到 Cube 的过程就是将平面数据立体化的过程,在这个过程中加入了从各个不同角度对数据的聚合。而从 Cube 到 SSRS 报表的过程又恰恰相反将立体化的数据平面化的结果。

分析上面的需求,其中需要娶到 Category, Subcategory, Calendar Year 以及 Reseller Sales Amount 的数据。SSRS 报表可以对平面化的数据非常快速的分组和聚合的,因此上面的需求我们整理一下就得到了这样的一个数据表原型。

假设我们基于上面的这张表去创建 Cube 的话,很显然 Cube Dimension 应该包含了 Product 和 Date 这两个维度和一个度量值维度- Reseller Sales Amount , 每一个维度的属性层次结构可以理解为在 Cube 空间中的一个轴。因此,Product 这个维度至少可以分出 Product Category 和 Product Sub Category 这两个属性层次结构,Date 维度我们假设这里只有 Calendar Year 这一个属性层次结构,那么再加上度量值维度就构成了 Cube 空间的四条轴,四条轴交汇定位到空间的一个点,这个点是一个单元格,它包含了 Reseller Sales Amount 的值。

这是从 Cube 空间体的角度来阐述从 DW 到 Cube 的变化,但是 SSRS 中表格数据中只支持二维数据组合,因此要把 Cube 空间的立体数据给拉平了再呈现回来。

创建报表并新建数据源,这时的数据源连接方式与之前连接到 SQL Server 数据库不同,连接的是 Analysis Services 。

新建 Dataset,并且指定刚才新建的数据源。因为数据源的改变,SSRS Dataset 中的 Query Designer 将对应的调整为支持 MDX 查询的界面。

Query Designer 中可以看到指定的分析服务的数据库以及各维度,层次结构和度量值组。

也支持编写 MDX 查询代码,特别是比较复杂的业务逻辑的情况下,就需要自己手工编写 MDX 查询。

我们直接使用拖拽的方式快速开发一个 MDX 查询报表,并且现在要做的就是让这几条轴交汇一下来展现我们扁平化的数据表原型。记住:每一个属性层次结构就是一条轴,包括度量值维度。这几条空间里的轴在数据表上最直接的反映就是形成列,每一条数据的形成就是四条轴在 Cube 空间交互的结果。

保存之后,看到 MDX 查询已经自动编写好了。

整理一下格式,看看这个 MDX 查询是怎么写的。

 SELECT NON EMPTY { [Measures].[Reseller Sales Amount] } ON COLUMNS,
NON EMPTY {
(
[Product].[Category].[Category].ALLMEMBERS *
[Product].[Subcategory].[Subcategory].ALLMEMBERS *
[Date].[Calendar Year].[Calendar Year].ALLMEMBERS
)
} DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME ON ROWS
FROM [Chapter 3 Cube]
CELL PROPERTIES VALUE, BACK_COLOR, FORE_COLOR, FORMATTED_VALUE, FORMAT_STRING,
FONT_NAME, FONT_SIZE, FONT_FLAGS

去掉一些不关键的属性,简化一下就是 -

SELECT NON EMPTY { [Measures].[Reseller Sales Amount] } ON COLUMNS,
NON EMPTY {
(
[Product].[Category].[Category].ALLMEMBERS *
[Product].[Subcategory].[Subcategory].ALLMEMBERS *
[Date].[Calendar Year].[Calendar Year].ALLMEMBERS
)
}ON ROWS
FROM [Chapter 3 Cube]

与前面在 Query Designer 上的查询结果相比一下这个 MDX 查询在 SQL Server Analysis Service 上面的查询结果,Query Desinger 的查询结果扁平化了,更容易理解成一个普通的数据表。而在这里,列头的构成比较复杂,它本想描述一下这种立体的感觉,无奈在二维平面的世界里它也描述不出来。

注意,这里的 MDX 查询在 Columns 只能是 Measure 度量值。 

创建好了 Dataset 之后就可以直接使用这个平面数据了,拖放一个 Matrix 过来。Matrix 和 Tabular 最大的区别就是 Matrix 可以直接形成行和列的聚合。

对比一下拖放之间和拖放之后的 Matrix 格局便于大家理解。Row 上放的应该是 Category 和 Subcategory,列上放的应该是 Calendar Year,被聚合的数据应该是 Reseller Sales Amount。但是这里,我们先放 Subcategory,然后在 Subcategory 基础上添加 Group - Category。

选中 Subcategory 然后右键添加一个 Group - Parent Group 。

Product Subcategory 可以按照 Category 分组,添加一个 Group Header。

添加完了之后的效果,不过接着就应该删除 Category 这一列,让 Category 这个元素显示在 Subcategory 元素之上,并且添加 Category 级别对 Reseller Sales Amount 的 SUM 聚合。

对比上下这种变化,基本上就完成了报表数据的分组聚合设计。

接着调整一下,然后上色。

为 Category 添加一个 Total。

基于 Calendary Year 也添加一个 Total。

添加完了后上上色,调整一下格式。

将标题 Subcategory 改成 Category ,并且设置 Subcategory 按照 Category 的点击来展现收缩和展开效果。

自此就已经完成了一个简单的 MDX 查询在 SSRS 报表上的展现。不过,如果要添加参数比如希望能够先筛选 Category 和 Subcategory,回到 Dataset 里的 Query Designer 添加 Parameter 。

保存并刷新,SSRS 为自动创建两个参数。

预览报表并选择参数。

最后查询出来的结果。


分析一下在 Query Builder 中的 MDX 查询语句,我就以 MDX Step By Step 上面的例子来说吧,这个 MDX 查询在 SSAS 查询分析器中没有问题。

但是同样的语句放到 Query Designer 中就有问题,提示这种错误。

The query cannot be prepared: The query must have at least one axis. The first axis of the query should not have multiple hierarchies, nor should it reference any dimension other than the Measures dimension.. Parameter name: mdx (MDXQueryGenerator)

其中要注意的有三点:

  • MDX Query 必须至少要有一个轴。
  • 第一个轴中的查询不能包含多个层次结构,只能有一个。
  • 除了 度量值维度 Measure Dimension 之外不能引用其它任何的维度。

再来看看我们的带参数的 MDX 查询语句。

SELECT  -- COLUMNS 轴也就是第一个轴上的维度是度量值维度
NON EMPTY { [Measures].[Reseller Sales Amount] } ON COLUMNS,
-- ROWS 上由多个属性层次结构的成员构成 SET 集
NON EMPTY {
(
[Product].[Category].[Category].ALLMEMBERS *
[Product].[Subcategory].[Subcategory].ALLMEMBERS *
[Date].[Calendar Year].[Calendar Year].ALLMEMBERS
)
}ON ROWS
FROM
-- 第三层查询基于前两层查询筛选之后的结果
(
-- 第二层查询,根据参数 Product Subcategory 并根据第一层查询的结果返回相应的 Subcategory
SELECT ( STRTOSET(@ProductSubcategory, CONSTRAINED) ) ON COLUMNS
FROM (
-- 第一层查询,根据参数 Product Category 决定了这个层次结构上所有的 Category 成员
SELECT ( STRTOSET(@ProductCategory, CONSTRAINED) ) ON COLUMNS
FROM [Chapter 3 Cube]
)
)

其中最重要的就是 STRTOSET 函数的使用,在 SSRS 加载的时候会首先列出所有 Product Category 成员供我们选择。 

就相当于 -

选择完了 Bikes 之后,Subcategory 刷新完然后选择 Mountain Bikes 和 Road Bikes

就相当于

整个 MDX 查询翻译到 SSAS 的就是

对比一下最终在 SSRS 上的报表,相当于把 MDX Query 的结果给扁平化了。

要注意的是 STRTOSET('[Product].[Category].[Bikes]', CONSTRAINED),它将一个字符串转化成了一个具体的集合,并且加上了 CONSTRAINED 那么在第一个参数字符串中就只能指定具体的层次结构中的成员,它有一个限定作用。

比如说如果想直接写上全部成员就会发生这样的错误。

The restrictions imposed by the CONSTRAINED flag in the STRTOSET function were violated.

如果去掉 CONSTRAINED,那么结果是OK的,类似的函数还有 STRTOMEMBER.

至于 STRTOSET 和 STRTOMEMBER 这两个 MDX 函数就不在这篇 SSRS 博客中详细解释了,这里只是通过例子对比大概描述了 MDX 查询参数化的过程和在 SSRS 报表上的使用。这种方式非常直接也比较简单,当然也还有其它传参数的方式,比如编写 Expression 等等在不同的场景下也会使用到。

没有写好的地方,欢迎大家积极补充和指正!

 
 

SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表的更多相关文章

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

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

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

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

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

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

  4. [译]SSRS 编写带参数的MDX报表

    编写MDX报表长久以来对于报表人员来说都比较痛苦. 当然如果你用查询设计器(Query Designer) 直接拖拉数据集那就很方便,但是你们有没有想过查询设计器是怎么创建MDX的.或者创建的参数是如 ...

  5. Oracle,Mysql ,SQL Server 三大数据库带参数的模糊查询, 拼接查询条件问题

    最近项目开发一直在不断切换数据库,有时候一条sql 要同时考虑多种数据库中的兼容问题 , 先总结一条模糊查询拼接查询条件的问题,后续追加总结. 目前使用   mybatis: 1. Oracle 中使 ...

  6. hibernate学习系列-----(5)hibernate基本查询下篇:hibernate聚合函数、分组查询及命名查询

    在上一篇中,大致学习了hibernate的基本查询:HQL基本查询,今天,继续昨天的步伐,继续学习hibernate的基本查询..... 1.hql聚合函数,先大致列一下hql的聚合函数有哪些吧: 在 ...

  7. vue 带参数的跳转-完成一个功能之后 之后需要深思,否则还会忘记

    我要写详细点,否则下次很容易忘记 写了一个页面,这个页面里面添加了 很多a 标签,跳转都是同一个页面,内容不一样,方法 首先 路由 设定好 routes:[ { path:'/aaa', name:' ...

  8. Python带参数的装饰器

    在装饰器函数里传入参数 # -*- coding: utf-8 -*- # 2017/12/2 21:38 # 这不是什么黑魔法,你只需要让包装器传递参数: def a_decorator_passi ...

  9. Qt带参数的信号和槽

    在Qt的开发过程中,信号带参数是很常见的,在使用带参数的信号槽时,有以下几点需要注意. 当信号和槽函数的参数数量相同时,它们的参数类型要完全一致. 信号和槽函数的声明: signals: void i ...

随机推荐

  1. (一)spring MVC基本概念和流程

    MVC的概念 Model(模型):包含数据和行为.不过现在一般都分离开来:Value Object(数据) 和 服务层(行为). View(视图):负责进行模型的展示,一般就是展示给用户的界面. Co ...

  2. crawler_java应用集锦9:httpclient4.2.2的几个常用方法,登录之后访问页面问题,下载文件_设置代理

    在工作中要用到android,然后进行网络请求的时候,打算使用httpClient. 总结一下httpClient的一些基本使用. 版本是4.2.2. 使用这个版本的过程中,百度很多,结果都是出现的o ...

  3. UML九种图汇总

    UML视频读,该文件开始起草.我不知道如何下手啊!我想先UML九图和总结的关系,然后开始用它的文件. 首先在地图上. UML的九种图各自是:用例图.类图.对象图.状态图.活动图.协作图.序列图.组件图 ...

  4. Android微信道共用,没有反应

    研究2日,寻找良好的比较完整的文章一天.发送链接:http://www.apkbus.com/android-138326-1-1.html 然而,按照上面的教程一步一步做.结果点击分享或无反应. 出 ...

  5. VTune使用amplxe-cl进行Hardware Event-based Sampling Analysis 0分析

    于BASH正在使用VTune进行Hardware Event-based Sampling Analysis 0分析: 结果(部分)例如以下: 版权声明:本文博客原创文章.博客,未经同意,不得转载.

  6. 归并排序 & 快速排序

    归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有 ...

  7. C# - object有哪些基本方法类有

    Name Description Equals(Object) Determines whether the specified object is equal to the current obje ...

  8. POI导出大量数据的简单解决方案(附源码)-Java-POI导出大量数据,导出Excel文件,压缩ZIP(转载自iteye.com)

    说明:我的电脑 2.0CPU 2G内存 能够十秒钟导出 20W 条数据 ,12.8M的excel内容压缩后2.68M 我们知道在POI导出Excel时,数据量大了,很容易导致内存溢出.由于Excel ...

  9. C语言运算符表(优先级)

    http://www.is.pku.edu.cn/~qzy/c/operator.htm

  10. 《Programming Hive》读书笔记(两)Hive基础知识

    <Programming Hive>读书笔记(两)Hive基础知识 :第一遍读是浏览.建立知识索引,由于有些知识不一定能用到,知道就好.感兴趣的部分能够多研究. 以后用的时候再具体看.并结 ...