现在的位置: 首页 > 综合 > 正文

MDX 查询的基本语法

2012年09月22日 ⁄ 综合 ⁄ 共 2962字 ⁄ 字号 评论关闭

基本语法

针对 DB2® Alphablox 立方体执行的 MDX 查询的基本语法如下所示:

SELECT {axisSpecification} ON COLUMNS,
{axisSpecification} ON ROWS
FROM cubeName
WHERE (slicerItems)

其中:

axisSpecification
是一个或多个元组的集合。可以以列表形式输入元组,也可以通过 CrossJoin 函数来“生成”元组。
cubeName
是已定义的 Alphablox 立方体的名称。
slicerItems
是一个元组(通常是用逗号分隔的成员列表),将对这个元组过滤查询结果集。如果有多个切片成员,则每个成员必须来自不同的维,并且不能在查询中指定的任何轴中引用该维。
 
以下几点包括有关 DB2 Alphablox 的上下文中 MDX 用法的重要信息。

  • 维只能在查询中的一个轴上出现。将维放在多个轴上的查询将由于出错而失败。
  • 虽然查询通常指定两个轴,但它可以指定零个或多个轴。还可以将 COLUMNS 轴指定为 AXIS(0) 以及将 ROWS 轴指定为 AXIS(1)。后续的每个轴将被指定为 AXIS(n),其中 n 是下一个连续整数。注意,显示查询结果数据的 DB2 Alphablox 应用程序(GridBlox、ChartBlox 或 PresentBlox)只能接受最多指定了两个轴的查询。作为 XML 数据集显示的查询可以接受任意个轴。
  • 在 DB2 Alphablox 中,MDX 中的关键字是不区分大小写的,但是 MDX 查询中的成员名在被方括号 [ ] 括住时是区分大小写的。当成员名未被方括号 [ ] 括住时,它们在被发送到服务器之前将被转换为大写。除非数据库中的所有成员名都是大写的,否则应该使用方括号语法。
  • 如果在需要成员的 MDX 函数中只包含维名称,则 DB2 Alphablox Cube Server 将返回一些使用 [dimensionName].currentMember 作为值的结果。

---------------------------------------------------------------------------------------

 
 

考虑这样一个场景,有一个大Cube存储着网站的访问历史数据,其中有一个维就是网站中各个网页的URL。用户这个貌似很合理的要求是这样地。用户指定一个URL,将这个URL做为Slicer进行切片,然后察看和该网页相关的多维数据。反映到MDX语句中呢,就是在MDX屁股后面再添上一个”Where ([URL].[User Defined URL])”,其中” User Defined URL”是用户要输入的页面地址。Ok,需求很明确,也很合理,指定页面察看嘛,用个Where就打发了。别高兴太早,问题在后面。用户输入正确的网页地址,ok,运转正常;用户输入一个错误网页地址,一个异常从UI上跳出来,说找不到这个Member。输入错误了当然找不到,问题是在ASP系统中俺们使用OWC来和后台service交互, 这错误没法捕获。换句话说,要么您就保证提交给serverMDX语句完全正确,要么就给用户蹦出一个谁也不明白的异常。如果您有把握说服用户喜欢上这个异常,您就不必往下看这篇文章,否则俺们就一起来看看如何避免不存在的Slicer提交给server

首先要作的工作是判断用户输入的这个Slicer(也可以理解为member,因为目前用户只是要求基于单个维度来切片,不保证用户看了我这篇文章后胃口大开要求同时输入多维进行切片)是否是一个存在的MemberFilter函数配合InStr函数可以搞定这个。

Filter( [Time].Members,InStr([URL].currentmember.name, "ProductView.asp"))

上面这段MDX干的活就是,遍历URL维中的所有member,如果这个member的名字包含“ProductView.asp”(这个就是用户输入的页面地址),ok,扔到一个新set里,最后把这个set做为输出。如果用户输入的页面地址不存在,也就是没有任何member的名字能够和这个页面地址匹配,这个新set就为空。俺们要做的事情,就是避免这个set为空。

那么怎么避免Filter函数得到的set为空呢?耍点小花招。看看下面的代码:

TopCount( Union(Filter( [URL].Members,InStr([URL].currentmember.name, " ProductView.asp ")), {[URL].DefaultMember}), 1)

必须承认这是一个讨巧的招,不过好使就行,是不是名门正派的套路,就管不了这么多了。首先让Filter函数得到的set{[URL].DefaultMember}做一个Union操作,这样如果Filter函数的结果set为空,则会返回set会至少包含一个{[URL].DefaultMember},保证了返回set肯定不为空。然后再在外面套一个TopCount函数,将排列在第一个member提取出来,这样,如果Filter函数不为空,整个结果就是Filter函数的输出,如果Filter结果为空集,则返回的是一个包含 [URL].DefaultMember的集合。需要说明的是DefaultMember是事先预定义的一个计算成员,其各个measure的值永远都是-1。至于为啥要定-1think

Ok,到这,俺们已经得到了一个包含且仅包含一个(真绕口,Rap?)Memberset,这个Member就是用来做 Slicer的原料。但是Slicer只可以是Tuple,不可以是Set,还得费点事将Set转换为Tuple。查遍MDX函数,找不到SetToTuple或者TupleToSet。看来只又再出偏招了。注意到Set的字符串形式是什么?”{[ ProductView.asp]}”Tuple的字符串形式是”([ProductView.asp])”,,,,get it Set转换为字符串,然后脱去前后两个大括号,再添上两个圆括号,ok,这不就是Tuple了吗 J 说的轻飘,写起来苦:

Where (StrToMember( mid(SetToStr(TopCount( Union(Filter( [URL].Members, InStr([URL].currentmember.name, "ProductView.asp]")), {[URL].DefaultMember}), 1)),2, Len(SetToStr(TopCount( Union(Filter( [URL].Members,InStr([URL].currentmember.name, " ProductView.asp]")), {[ URL].DefaultMember}), 1))))))

这就是最后这个Slicer的模样,是不是看上去有些臃肿状。没办法,在向大家介绍MDX的时候,为了安抚人心,俺常说MDX语法虽然复杂,但是编写的时候往往比SQL来的简洁。但是,在实际应用中,正因为MDX太强大,为了迎合客户的种种BT要求,写出的MDX语句往往也很BT。这正应验了Leader的名言:客户有多BT,程序就有多BT

抱歉!评论已关闭.