精华内容
下载资源
问答
  • MDX 多维数据表达语言

    2018-12-24 08:47:18
    全面且逐一介绍MDX语法,函数操作,并且每个语法函数分开,可逐一查看
  • mdx多维表达式

    2013-10-14 17:25:26
    关于mdx资源的实用表达式,系统的对mdx进行描述,方便进行应用
  • MDX多维查询

    千次阅读 2016-10-25 09:56:48
    MDX(Multidimensional Expressions)是多维 数据库(OLAP 数据库)的查询语言.Mondrian 会解析MDX,转换成SQL 来查询关系数据库(可能是多条查询)。MDX 的内容很多,功能强大,这里只介绍最基础和最重要的部分。 ...

    MDX

    Created 星期一 24 十月 2016

    MDX(Multidimensional Expressions)是多维 数据库(OLAP 数据库)的查询语言.
    Mondrian 会解析MDX,转换成SQL 来查询关系数据库(可能是多条查询)。
    MDX 的内容很多,功能强大,这里只介绍最基础和最重要的部分。

    1 基本语法

    以下是里两条MDX 查询语句及其查询结果
    ð 语句1:
    SELECT
    { [Measures].[Dollar Sales], [Measures].[Unit Sales] } on columns,
    { [Time].[Q1, 2005], [Time].[Q2, 2005] } on rows
    FROM [Sales]
    WHERE ([Customer].[MA])

    语句 2
    SELECT
    { [Time].[Q1, 2005], [Time].[Q2, 2005], [Time].[Q3, 2005] } on columns,
    { [Customer].[MA], [Customer].[CT] } on rows
    FROM Sales
    WHERE ( [Measures].[Dollar Sales] )
    第一条语句查询对[Customer].[MA]这个客户在 2005 年第一、第二季度的销售额、报表期销售额。
    第二条语句查询对[Customer].[MA], [Customer].[CT]这两个客户在 2005 年前三个季度的销售额。
    可以看到,mdx 有类似 sql 的结构,同样有 select、from、where 这三部分。但也有很多不同。

    1. Select 字句指定一个集合,把它放到某个上。
    2. From 字句说明要从哪个数据立方体来查询。
    3. 方括号([])用于维度名、层次名、维度成员名,避免名字和函数混淆(函数名

    是不加方括号的)。

    1. Where 字句指定切片,即对不出现在轴上的维度的成员的限定。
    2. Mdx 没有 group by 字句。其实分组是隐含的。
    3. Mdx 没有 order by 字句。排序只会对某个轴进行,通过使用排序函数。
    4. 和 sql 一样,mdx 也是不区分大小写的,并且可以随意分行。
    5. Mdx 中也可以包含注释,除了支持 sql 的--注释外还支持//和/* ... */注释。

    2 轴

    用 on {axis}语法来把维度分配到轴(Axis,复数 Axes)上,一个查询可以有多个轴。
    不同轴用逗号分隔,分配的顺序是没关系的。但如果把轴调换(如 A on columns, B on rows 改成 A on rows, B on columns),结果的行和列也会转置过来。
    轴用 axis(0),axis(1),axis(2)...表示,前五个轴可以使用别名 Columns,Rows,Pages,Chapters,Sections。因此 on Columns 等价于 on axis(0)。超过 5 个轴时只能用 axis(5),axis(6)...来表示(极少会需要这么多的轴)。
    很多实现(包括 Mondrian)支持仅用数字表示轴,因此 on Columns 可以写成 on 0。axis(0)和别名表示可以混用,例如下面语句是可以的:
    SELECT
    { [Time].[Q1, 2005], [Time].[Q2, 2005] } on axis(0),
    { [Customer].[MA], [Customer].[CT] } on rows
    FROM Sales
    轴必须从 0 开始,并且连续,不能跳过。下面的是不可以的:
    SELECT
    { [Time].[Q1, 2005], [Time].[Q2, 2005] } on rows,
    { [Customer].[MA], [Customer].[CT] } on pages
    FROM Sales
    错误,跳过了轴 axis(0)(columns) 。

    在大多查询中,轴一般是两个。一个轴也可以,甚至 0 个轴。
    如果轴多于两个,就没法在平面上表示。如果维度多于两个,需要把多个维度(交叉后)放到一个轴上。

    3 切片维度

    切片(Slice)维度就是出现在 MDX 语句 WHERE 子句中的维度,跟 SQL 一样,表示对数据集的限制。例如 MDX 语句:
    SELECT
    {[Product].[All Products].[Food], [Product].[All Products].[Drink]} ON COLUMNS
    FROM [Sales]
    WHERE [Time].[Year].[2005]
    限制了查询的数据范围,只限于 2005 年。语法和 SQL 不一样,[Time].[Year].[2005](是一个元组)本身就表示了一个条件。这可以看成对数据立方体从某个方向进行切片(从 Time维度的方向)得到一个子立方体,因此叫切片
    切片维度不会出现在轴上。上面的时间维度不会出现在轴上。
    一个维度不能同时出现在轴维度(SELECT 的维度)和切片维度上。

    默认成员

    如果一个维度既没有出现在轴维度上,也没有出现在切片维度上,就会用维度的(默认层次的)默认成员进行切片。一般维度的默认成员是"All xxx" ,因此默认是对这个维度所有成员的数据进行聚集操作。例如:
    SELECT {[Time].[Year].Members } ON COLUMNS
    FROM [Sales]
    Product 维度没有出现在轴维度和切片维度上。如果 Product 的默认成员是[All Products],就会查询所有产品的销售额汇总,符合人的习惯。上面语句相当于:
    SELECT {[Time].[Year].Members } ON COLUMNS
    FROM [Sales]
    WHERE [Product].[ All Products]
    维度有一个函数 defaultMember 可以返回维度的默认成员,因此也相当于:
    SELECT {[Time].[Year].Members } ON COLUMNS
    FROM [Sales]
    WHERE [Product]. defaultMember
    除了 Product 维度,其他没有出现在轴维度和切片维度上的维度也是一样的。

    度量维度(为了一致可以把度量看成一个维度:Measures 维度)是没有"All xxx"成员的,它的默认成员可以明确设置,如果没设置,就是第一个度量。如果默认度量是[Store Sales],
    下面的查询
    SELECT {[Time].[Year].Members } ON COLUMNS
    FROM [Sales]

    SELECT {[Time].[Year].Members } ON COLUMNS
    FROM [Sales]
    WHERE [Measures]. [Store Sales]
    是等价的。
    一个维度的默认成员、是否有 All 成员(一般都应该有),是可以在 Schema 文件中设置的。
    如果没有明确设置默认成员,默认成员就是 All 成员,如果没有 All 成员,默认成员就是第一个成员。

    4、元组和集合

    元组和集合是 MDX 中的两种数据类型,也是 MDX 语句的构件。

    元组

    元组(Tuple)就是一个或多个维度的成员的组合
    当一个元组有多个维度时,必须用括号括起来
    ([Customer].[Chicago, IL], [Time].[Jan, 2005])
    一个元组可以代表立方体的一个切片
    以这种语法构造的元组可以直接用于
    SELECT
    { ( [Time].[2005], [Measures].[Dollar Sales],
    ( [Time].[Feb, 2005],[Measures].[Unit Sales] )
    } ON COLUMNS ,
    { [Product].[Tools], [Product].[Toys]} ON ROWS
    FROM [Sales]
    元组不能嵌套

    where 字句也是一个元组,用以指定一个数据切片

    集合

    集合(Set)只是一个一批已排序的元组。一个集合可以有一个元组,多个元组,或者是空的。不像数学上的集合,MDX 集合一个元组可以出现多次,而且顺序是重要的。
    通常的指定集合的方式是把一个元组列表用花括号括起来。如{ [Customer].[MA],
    [Customer].[CT] }就表示一个集合,集合里是客户维度的两个成员。
    一个集合中的所有元组必须有同样的维度性质,即所表示的维度及其顺序。
    使用下面的集合将会报错,因为维度的顺序不一样:
    { ( [Time].[2005], [Measures].[Dollar Sales] ), ( [Measures].[Unit Sales], [Time].[Feb, 2005] ) }
    很多函数都可以返回一个集合

    5、维度成员

    要把维度成员放在轴上,可以列举维度的成员,例如{ [Customer].[MA], [Customer].[CT] }。也可以通过范围语法或一个函数得到成员的集合。

    成员范围

    冒号(:)语法可以表示成员范围。冒号前后是同一个层次的起点和终点两个成员。
    SELECT
    { [Time].[2003] : [Time].[2008] } on columns,
    { [Product].[Drinks] : [Product].[Bread] } on rows
    FROM [Sales]
    时间维度表示 2003 年到 2008 年(6 个成员),产品维度表示从 Drinks 到 Bread。这通常跟排序方式有关。

    集合里可以包含子集合。例如下面集合,包含 2001 年的前三个月跟后三个月。
    { { [Time].[January-2001] : [Time].[March-2001] } ,{ [Time].[October-2001] : [Time].[December-2001] } }

    全部成员

    大多时候需要得到一个维度、层次、层的全部成员,这个时候可以使用.Members 操作(函数)。比如[Time].[Years].Members 可以得到所有年份。
    SELECT
    { [Time].[Years].Members} ON COLUMNS,
    { [Product].[Line].Members} ON ROWS
    FROM [SteelWheelsSales]
    WHERE [Measures].[sales]
    这个语句查询所有年份、所有产品线的销售额,把年份放在列上,产品线放在行上。

    下级成员

    有时候需要得到某个成员的下一层次的全部成员,这是需要用.Children 函数。这在下钻操作时经常用到。
    例如要得到产品线 Classic Cars 下的所有产品,可以这样[Product].[Line].[Classic
    Cars].Children。[Product].[Line].[Classic Cars]是 Product 维度 Line 层的一个成员。
    .Children 只能得到直接下级成员,如果需要多级,需要使用 Descendants()函数。语法是:
    Descendants (member [, [ level ] [, flag]] )
    Descendants 返回 member 成员下 level 层的成员,可选标志 flag 有多个选项,以设置包含最下一层上面的哪些层的成员。
    以下是一个例子,查询 Tools 和 Toys 两类产品在 2005 年各月的销售额,因为年和月两个层次中间有一个季度层次,所以不能用[Time].[2005].Children。
    SELECT
    { [Product].[Tools], [Product].[Toys] } ON COLUMNS,
    Descendants ([Time].[2005],[Time].[Month],SELF_AND_BEFORE) ON ROWS
    FROM Sales
    WHERE [Measures].[Dollar Sales]
    flag 设为 SELF_AND_BEFORE,可以看到行上包含了 2005 年和各个季度(如果设为
    SELF 则不会包含) 。

    成员属性

    有时要获取维度成员的属性(维表上的某些列),这时可以使用 dimemsion properties子句。dimemsion关键字可以省略。
    以下查询同时获取客户所在地的邮编属性
    SELECT
    { [Customer].[Akron, OH].Children }
    DIMENSION PROPERTIES [Customer].[Zip Code]
    on columns,
    { [Product].[Category].Members } on rows
    FROM Sales
    WHERE ([Measures].[Units Sold], [Time].[July 3, 2005])

    6、集合操作

     

    NON EMPTY

    在多维空间,数据很多时候是稀疏的。比如:比如,不是每一个产品都销售给了所有的客户,不是每一个客户在每个时期都购买了产品。如果按维度所有成员交叉得出报表,就会有很多空行、空列。
    要从查询结果去掉这些空行
    SELECT
    { [Time].[Jan,2005],[Time].[Feb,2005] } ON COLUMNS ,
    NON EMPTY { [Product].[Toys], [Product].[Toys].Children } ON ROWS
    FROM Sales
    WHERE ([Measures].[Dollar Sales], [Customer].[TX])
    这样空行就去掉了。non empty 可用于任何轴上。

    CROSS JOIN

    很多时候,我们需要对两个不同的集合进行交叉,也就是要得到两个集合成员的所有组合。CrossJoin()函数就是用来得到组合的最直接方式,它的语法是 CrossJoin (set1, set2)
    以下语句在每个季度下分出两个度量
    SELECT
    CrossJoin (
    { [Time].[Q1, 2005], [Time].[Q2, 2005]},
    { [Measures].[Dollar Sales], [Measures].[Unit Sales] }
    ) ON COLUMNS,
    { [Product].[Tools], [Product].[Toys] } ON ROWS
    FROM Sales
    CrossJoin 的结果是一个集合。因此支持CrossJoin 嵌套。

     

    FILTER

    Filter 函数用来筛选一个集合,它以一个集合和一个 boolean 表达式为参数
    Filter (set,boolean-expression)。
    例如,以下表达式会返回关联的产品销售额至少为500 的产品分类的集合。
    Filter (
    { [Product].[Product Category].Members },
    [Measures].[Dollar Sales] >= 500
    )
    要求销售额至少为 150 并且销售额要至少在成本的1.2 倍以上
    Filter (
    { [Product].[Product Category].Members },
    ([Measures].[Dollar Sales] >= 1.2 *[Measures].[Dollar Costs])
    AND [Measures].[Dollar Sales] >= 150
    )

     

    ORDER

    Order()函数用于对一个集合进行排序,语法:
    Order (set1, expression[,ASC| DESC | BASC | BDESC])
    SELECT
    { [Measures].[Dollar Sales] } on columns,
    Order (
    [Product].[Product Category].Members,
    [Measures].[Dollar Sales],
    BDESC
    ) on rows
    FROM [Sales]
    WHERE [Time].[2004]

    7、计算成员

    在 sql 中可以增加计算出来的列,MDX 中同样也可以,在 MDX 中叫计算成员(CalculatedMember)。因为MDX 操作的是多维数据,计算成员实际是给一个维度增加成员。
    语法:
    with
    member 成员标识 as '表达式' [, 属性...]
    select ...
    表达式用单引号引注。
    以下例子增加一个新的度量[Avg Sales Price]
    WITH
    MEMBER [Measures].[Avg Sales Price] AS
    '[Measures].[Dollar Sales] / [Measures].[Unit Sales]'
    SELECT
    { [Measures].[Dollar Sales], [Measures].[Unit Sales],
    [Measures].[Avg Sales Price]
    } on columns,
    { [Time].[Q1, 2005], [Time].[Q2, 2005] } on rows
    FROM Sales
    WHERE ([Customer].[MA])

    公式优先级(Solve Order)

    当不止一个维度增加了计算成员时,由于每个维度的成员都有计算公式,在这些维度的交叉点上,就可以有多种计算顺序。这时候就不需要考虑公式优先级的问题。因此引入了 SOLVE_ORDER 属性
    WITH
    MEMBER [Measures].[Avg Sales Price] AS
    '[Measures].[Dollar Sales] / [Measures].[Unit Sales]',
    SOLVE_ORDER=0
    MEMBER [Time].[Q1 to Q2 Growth] AS
    '[Time].[Q2, 2005]- [Time].[Q1, 2005]',
    SOLVE_ORDER=1
    SELECT
    { [Measures].[Dollar Sales], [Measures].[Unit Sales],
    [Measures].[Avg Sales Price]
    } on columns,
    { [Time].[Q1, 2005], [Time].[Q2, 2005], [Time].[Q1 to Q2 Growth] } on rows
    FROM [Sales]
    WHERE ([Customer].[MA])

    8、命名集合

    命名集合(Named Set)允许预先定义的一个集合,供后面的语句使用。语法和计算成员类似。
    with
    set 集合标识 as '集合表达式'
    select ...

    WITH
    SET [User Selection] AS '{ [Product].[Action Figures], [Product].[Dolls] }'
    MEMBER [Product].[UserTotal] AS 'Sum ( [User Selection] )'
    SELECT
    { [Time].[Jan, 2005], [Time].[Feb, 2005] } ON COLUMNS,
    { [Product].[Toys], [User Selection], [Product].[UserTotal] } ON ROWS
    FROM Sales
    WHERE ([Measures].[Unit Sales])

    9、函数

    http://mondrian.pentaho.com/documentation/mdx.php

    列出一些重要的,按返回类型来分类。

    成员函数

    .currentMember
    .parent
    .prevMember/.nextMember
    .firstChild/.lastChild
    .firstSibling/.lastSibling
    Ancestor(<Member>, <Level>)
    Ancestor(<Member>, <Numeric Expression>)

    LAG 返回当前成员开始往前数的本层的第几个成员.
    <Member>.Lag(n)
    n是索引,0 是它本身,1是前一个(.prevMember)

    LEAD 类似 Lag(),但方向相反

    OpeningPeriod 返回某个层次上第一个后代成员
    语法:OpeningPeriod([<Level>[, <Member>]])。
    ClosingPeriod 返回某个层次上最后一个后代成员

    PARALLELPERIOD 返回一个成员同层次对应位置的成员
    ParallelPeriod([<Level>[, <n>[, <Member>]]])在时间维度上取同期(如上年同期)等的时候需要用到它。

    集合函数

    前面介绍的 members、children、descendants、crossJoin、filter、order 都是集合函数
    union
    合并两个集合。语法:Union(set1,set2[, ALL]) All 标志指示保留重复元素
    Except
    从set1里去除set2的元素,即求两个集合的差。Except(set1,set2[, ALL])
    Head/Tail
    返回集合Head/Tail元素 。 Head/Tail(set[, <count>))。
    .SIBLINGS
    返回成员的兄弟成员,包括它自己。<Member>.Siblings。
    .MEMBERS
    返回维度/层次的成员。<Dimemsion>.Members
    DESCENDANTS
    返回成员的后代成员。Descendants (member, [level[,flag]])
    flag 可以是:SELF、BEFORE、SELF_BEFORE_AFTER、LEAVES、AFTER、SELF_AND_BEFORE、SELF_AND_AFTER。

    DrillDownLevel(set,[level])
    下钻(一级)成员。
    DrillDownLevelBottom(set,index[,level][,numeric])
    下钻最下一级成员。
    DrillDownLevelBTop(set,index[,level][,numeric])
    下钻最上一级成员。
    DrillDownMember
    下钻集合2中的成员.DrillDownMember(set1,set2[,Recursive])

    TopCount 返回前n个数据的集合
    <Set> TopCount(<Set>, <Numeric Expression>, <Numeric Expression>)
    <Set> TopCount(<Set>, <Numeric Expression>)

    (TopCount, BottomCount, TopPercent, Hierarchize ,etc.)

    统计函数

    count (set [,INCLUDEEMPTY])
    可选标记指定是包含无数据的元组
    Sum (set [,数值表达式]])
    max/min/median/avg(set [,数值表达式]])

     

    逻辑函数

    IS
    object is object2。
    例如:
    [Jan 2000].PrevMember IS NULL
    [Jan 2000].Level IS [Time].[Month]

    ISEMPTY
    判断一个值是否为空。语法:IsEmpey(表达式)。

    字符串函数

    NAME
    返回维度、层次等的名称。语法:<Dimension/Hierarchy/Level/Member>.Name
    PROPERTIES
    返回成员的属性值。语法:<Member>.properties(<属性名>)

    其他函数

    这里是一些返回类型不定的函数。
    LiF
    根据条件返回值,类似Excel 的If 函数。语法:lif(<布尔表达式>, <值1>, <值2>)。
    ITEM
    根据索引返回集合中元素。语法:item(set, <index>)。
    返回类型一般为元组。

     

    展开全文
  • 多维表达式 (MDX) 语言介绍.....................
  • MDX多维表达式学习.ppt

    2020-11-01 12:14:20
    4. 创建用户定义函数 用户定义函数可用支持 COM 接口的任何编程语言创建 用户定义函数可...Visual Basic 中的子程序也可使用例如如果想要在 MDX 语句中使用 MyVoidFunction) 函数可采用下面的语法 CALL(MyVoidFunction
  • 事实表有status代表状态值(1,2,3,4,5,6),我想统计这些不同状态的sum数量。如何使用MDX多维表达式进行编写?计算成员表达式如何编写呢?大侠们赶紧帮助小弟一把。非常感谢!
  • 多维数据查询 OLAP 及 MDX 语言学习整理 OLAP 为了满足业务管理和决策的报表系统(包括传统报表、数据仓库、OLAP等)也被创建出来,企业主管通过报表了解企业的总体运行状态。 但是,随着企业间竞争的加剧和市场节奏...

    多维数据查询 OLAP 及 MDX 语言学习整理
    OLAP
    为了满足业务管理和决策的报表系统(包括传统报表、数据仓库、OLAP等)也被创建出来,企业主管通过报表了解企业的总体运行状态。
    但是,随着企业间竞争的加剧和市场节奏的进一步加快,企业的日常管理需要对关键业务指标的更加实时的监控和反馈。比如:制造业需要更及时的仓库调度、金融业需要更实时的风险防范、电信业需要更及时的服务指标监控。于是,越来越多的企业提出实时企业的要求,传统的ERP等信息系统和报表系统无法满足这些需求。实时业务监控解决方案旨在更好支撑客户此类需求。
    当今的数据处理大致可以分成两大类:联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。OLTP是传统的关系型数据库的主要应用,主要是基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。

    OLAP技术非常多的特性,概括起来主要有如下几点特性:

    OLAP技术是面向分析人员、管理人员的;

    OLAP技术对数据访问通常是只读的,并且一次访问大量数据;

    OLAP技术是面向主题的多维数据分析技术。

    OLAP(On-Line Analysis Processing)在线分析处理是一种共享多维信息的快速分析技术;
    OLAP利用多维数据库技术使用户从不同角度观察数据;OLAP用于支持复杂的分析操作,侧重于对管理人员的决策支持,可以满足分析人员快速、灵活地进行大数据复量的复杂查询的要求,并且以一种直观、易懂的形式呈现查询结果,辅助决策。
    上面是OLAP的一些不同的解释,本文将从以下几个方面介绍OLAP。
    Cube立方体的概念:
    在Bi领域,cube是一个非常重要的概念,是多维立方体的简称,主要是用于支持联机分析应用(OLAP),为企业决策提供支持。Cube就像一个坐标系,每一个Dimension代表一个坐标系,要想得到一个一个点,就必须在每一个坐标轴上取得一个值,而这个点就是Cube中的Cell。
    Cube是联机分析的关键。他们是一种多维结构,包含原始事实数据、聚合数据,这些数据聚合允许用户快速进行复杂的查询,Mdx语言就应用它更是如鱼得水。
    Cube包含两个基本概念:维度和度量

    维度(Dimension):维度提供了分类描述,表示一类分析角度,用户通过维度分析度量数据。比如上图中的三个维度:时间、产品、地域

    度量(Measures):度量表示用来聚合分析的数字信息,度量的集合组合成了一个特殊的维度。如数量、销售额等。

    级别(Level):一个维度上可以包含的层次结构,表示特定的分类。如上图中地域维度可以包含的级别层次级:国家、省、市;时间维度包含的级别层次包含:年、季度、月、日等。

    成员,是最重要的概念之一,一个成员是维度(包括度量)上的项目值。如上图时间维度上”年“级别的成员就包含:2000,2001,2002,2003…月成员包含:1、2、3等。

    计算成员,是一种运行通过特殊表示式动态计算的成员。也就形成了度量(Measures)的结果。计算成员不影响现有的Cube数据,它基于cube数据,通过各种数学表达式和各种函数定义,可以创建复杂的表达式。任何动态分析功能,都可以通过计算成员实现,比如实现占比,同期比等等。

    维度的概念
    例如一个维度(Dimension):Region
    该维度下有四个级别(Levels):country、province、city、county,他们属于层次集合(Hierarchy)
    通过维度和级别我们可以定义一个元素(Member)如:
    Region.Levels(1).members(2)=china
    Region.Levels(2).members(3)=shanghai

    展开全文
  • MDX语言学习

    2021-04-25 16:10:59
    因为商业智能的一项关键技术是多维数据库,访问多维数据库时使用SQL语言是不适用的,我们需要使用另一种语言:MDX。更深一步讨论,MDX包含两种最主要的用途:SQL语言可以查询和管理关系型数据库。类似的,MDX语言可以...

    MDX


    概述

    ​ 如果我们请教任何一位熟悉关系型数据库的朋友:“在关系型数据库方面,什么是最核心的技术?”那么答案多半是“SQL语言”。同样的道理,在BI领域,可以认为MDX语言是最核心的技术。因为商业智能的一项关键技术是多维数据库,访问多维数据库时使用SQL语言是不适用的,我们需要使用另一种语言:MDX。更深一步讨论,MDX包含两种最主要的用途:SQL语言可以查询和管理关系型数据库。类似的,MDX语言可以查询和管理多维数据库。

    Mondrian

    Pentaho Analysis Services,即Mondrian(项目代号),是Pentaho 的多维分析、OLAP 解决方案。Mondrian 就是一个OLAP 引擎,而且是一个ROLAP 引擎,ROLAP 指的是使用关系数据库的OLAP。它本身不管理数据的储存,这是由关系数据库来做的,它通过JDBC 来访问数据。这样可以大大减少OLAP 引擎的复杂性,而且可以使用很多种数据库。
    它实现了这些规范:

    1. MDX(多维查询语言,相当于数据库的SQL)
    2. XMLA(通过SOAP 使用OLAP)
    3. olap4j(Java API 规范,相当于JDBC 之于关系数据库)
      Mondrian 采用开源协议是Eclipse Public License。

    基本概念

    Cube

    image-20210325154248357

    schema

    多维数据的事实表、维表、聚集表等存储于数据库中,属于物理模型;而数据立方体、维度、度量这些概念属于逻辑模型。

    多维分析引擎必须要理解逻辑模型,并能够映射到物理模型上。多维数据的模式(Schema)就是用来描述这个逻辑模型以及到物理模型的映射的。模式(Schema)是多维数据库的元数据。

    MDX

    ​ MDX是这样一种语言,它可以表达在线分析处理(Online Analytical Processing,OLAP)数据库上的选择、计算和一些元数据定义等操作,并赋予用户表现查询结果的能力。但与其他一些OLAP语言不同的是,它不是完全用于格式化报表的语言。MDX查询的结果必须经过某种处理以使它看起来像一个电子制表、图表或者其他的输出形式,这样才能返回到客户程序。这和SQL查询关系数据库的工作方式及其相关的应用编程接口(API)的工作方式非常相似。

    常见多维分析操作

    • 下钻:从高层次向低层次明细数据穿透(全球下钻到东亚)。
    • 上卷:和下钻相反,从低层次向高层次汇聚(日本上卷到远东)。
    • 切片:将一个或多个维度设置为固定值,观察剩余的维度(将文化的维度限定为宗教)。
    • 切块:与切片类似,将维度从一个变成多个(文化的维度限定为宗教、文学、戏曲)。
    • 旋转:将数据映射到一张二位表(行列置换)。

    查询基础

    使用FoodMart.xml进行查询

    • 查看1997年前两个季度加利福尼亚州的销售额与成本
    SELECT
    {[Measures].[Store Cost], [Measures].[Unit Sales]} ON COLUMNS,
    {[Time].[1997].[Q1],[Time].[1997].[Q2]} ON ROWS
    FROM [Sales]
    WHERE {[State Province].[CA]}
    

    image-20210318160611299

    • 显示两个州的前三季的销量,列表示季度,行表示州
    SELECT
    {[Time].[1997].[Q1],[Time].[1997].[Q2],[Time].[1997].[Q3]}  ON COLUMNS,
    {[State Province].[CA],[State Province].[OR]} ON ROWS
    FROM [Sales]
    WHERE {[Measures].[Store Cost]}
    

    image-20210318161945803

    在查询中,SELECT、FROM和 WHERE是表示查询的不同部分的关键字。MDX查询的结果本身是一个网格,本质上是另一个多维数据集。将查询的多维数据集的维度反映在结果的轴上,该查询通过名称“rows”和“columns”进行引用。在MDX术语中,轴(axis)指的是查询结果的边或者维度。采用“轴”这个术语而不是“维度”,使得区分查询的多维数据集的维度与结果的维度变得相对简单。而且,每个轴都可以是多个多维数据集的维度的组合

    (1)关键字SELECT 后带需要检索内容的子句。
    (2)关键字 ON 和轴的名称一起使用,以指定数据库的维度显示位置。该示例查询将度量显示为列,将时间段显示为行。
    (3) MDX用大括号引用来自某个特定维度或者多个维度的一组元素。这个简单的查询在其两个轴中的每一个上都只有一个维度(度量维度和时间维度)。元素间用逗号,)隔开。元素名称用方括号[]引用,并且不同组成部分之间用点号(.)分隔。
    (4)在一个MDX查询中,可以指定数据库的维度如何在查询结果的轴上布局。上述查询将度量布局成列,将时间段布局成行。不同查询的轴的数量可能不同。前三个轴以“columns”、“"rows”及“pages”命名,以在概念上与打印的报表相匹配(可以用其他方式命名它们。尽管这个简单的查询在结果的每个轴上只显示一个维度,但当多个维度映射到结果的同一个轴上时,每个映射维度的成员构成一个组合,轴上的每个单元槽都会与一个这样的组合相关联。
    (5) MDX查询中FROM子句指明用于查询数据的多维数据集。这与结构化查询语言(Structured Query Language,SQL)中指定用于查询数据表格的 FROM子句类似。
    (6)WHERE子句指定在列或行(或者其他的轴)上不出现的多维数据集其他维度的成员。如果不对某个维度指定一个成员,MDX将使用默认值(这里忽略该查询中的括号,直到讨论元组时再作讨论)。WHERE子句是可选的。
    一旦数据库确定了查询结果的单元,将会用查询的多维数据集的数据填充它们。MDX与SQL一样使用SELECT、FROM 及 WHERE等关键字。但是根据基于MDX的教学经验,请注意:假如熟悉SQL及其 SELECT、FROM和WHERE 的使用方法,那么在学习MDX时请尽量忘记SQL,它们的语义和含义非常不同,尝试将SQL 概念应用到MDX上很可能造成混淆。

    轴框架:名称与编号

    ​ 使用“on columns/rows/pages/etc”语法表明要将成员显示在列、行,或查询结果的其他轴上。轴可以用任何顺序指定。上一个查询如果用下面所示的语句编程,将同样有效并且结果完全相同。

    SELECT
    {[Time].[1997].[Q1],[Time].[1997].[Q2],[Time].[1997].[Q3]} 
    ON ROWS,
    {[State Province].[CA],[State Province].[OR]} 
    ON COLUMNS
    FROM [Sales]
    WHERE {[Measures].[Store Cost]}
    

    使用轴编号通过声明指定查询中的轴

    SELECT
    {[Time].[1997].[Q1],[Time].[1997].[Q2],[Time].[1997].[Q3]} 
    ON axis(0),
    {[State Province].[CA],[State Province].[OR]} 
    ON axis(1)
    FROM [Sales]
    WHERE {[Measures].[Store Cost]}
    

    image-20210318173927057

    短语on axis(n)指明哪些成员要在编号为n的轴上显示。当前,名称与如下的数字编码是对称的:

    0Columns
    1Rows
    2Pages
    3Chapters
    4Secrions

    也可以混合使用编号,但是不能冲突 比如 ROWS + axis(1)

    SELECT
    {[Time].[1997].[Q1],[Time].[1997].[Q2],[Time].[1997].[Q3]} 
    ON ROWS,
    {[State Province].[CA],[State Province].[OR]} 
    ON axis(0)
    FROM [Sales]
    WHERE {[Measures].[Store Cost]}
    

    使用轴1的查询必须也使用轴0,使用轴2的查询必须同时使用轴1和轴0。查询中不能跳过前面的轴,否则会出错。下面的程序不能运行,因为它跳过了轴1:

    Mondrian Error:Axis numbers specified in a query must be sequentially specified, and cannot contain gaps. Axis 0 (COLUMNS) is missing.

    SELECT
    {[Time].[1997].[Q1],[Time].[1997].[Q2],[Time].[1997].[Q3]} 
    ON axis(1),
    {[State Province].[CA],[State Province].[OR]} 
    ON axis(2)
    FROM [Sales]
    WHERE {[Measures].[Store Cost]}
    

    ​ 如果把一个MDX查询的结果看作是一个超多维数据集(或者子多维数据集),并且把每个轴看作该超多维数据集的一个维度,那么就会明白跳过一个轴会出问题。

    大小写敏感与布局

    MDX既不是大小写敏感的,也不是一行一行处理的。例如,下面两个程序片断同样有效:

    SELECT {[Time].[1997].[Q1],[Time].[1997].[Q2],[Time].[1997].[Q3]} ON COLUMNS,...

    SELECT {[Time].[1997].[Q1],[Time].[1997].[Q2],[Time].[1997].[Q3]} ON columns,...

    可以随心所欲地混用字母大小写,对于语言的关键字,大小写无所谓。

    至于名称,对于 MDX提供者而言,大写可能有影响,也可能没有。

    对于 Analysis Services或 Essbase,大小写没有影响,尽管后面会碰到某些 Essbase关心大小写的情况。

    在哪里放置空格及行在哪里结束,同样没有影响,可以用下面的代码重写前面的程序片断:

    SELECT {
     [Time].[1997].[Q1],
     [Time].[1997].[Q2],
     [Time].[1997].[Q3]
    } 
    ON 
    COLUMNS,
    

    构造简单的MDX

    先建立一个小的词汇表,然后查看一些最简单且最常用的操作符和函数。

    这里将对它们做个简单的介绍并描述通常应如何使用

    这里将讨论的函数和操作符包括:

    逗号(,)和冒号(😃

    在讨论这些函数和操作符时,将使用术语“集(set)”。集是MDX中相当重要的概念,

    SELECT
    NON EMPTY {[Measures].[Store Cost]} ON COLUMNS,
    NON EMPTY Hierarchize(Union(CrossJoin({[Customers].[USA].[CA]}, {[Time].[1997].[Q1].[1]}), Union(CrossJoin({[Customers].[USA].[CA]}, {[Time].[1997].[Q1].[2]}), CrossJoin({[Customers].[USA].[CA]}, {[Time].[1997].[Q1].[3]})))) ON ROWS
    FROM [Sales]
    

    在每个维度的每个级别上,该级别的成员按照特殊的顺序排列(通常按照成员键或者名称排列)。当这个排列顺序有某种意义时,将来自同一级别的成员作为端点,并用冒号隔开,这表示“这两个成员及其中间的所有成员”这样按照指定的顺序排列的成员构成一个“集”。

    • 查询1997年1月到6月进口啤酒到体育月刊销售额
    SELECT
    {[Time].[1997].[Q1].[1] : [Time].[1997].[Q2].[6]} ON COLUMNS,
    {[Product].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Portsmouth].[Portsmouth Imported Beer]:
    [Product].[Non-Consumable].[Periodicals].[Magazines].[Sports Magazines].[Mighty Good].[Mighty Good Monthly Sports Magazine]
    } ON ROWS
    FROM [Sales]
    WHERE {[Measures].[Unit Sales]}
    

    ​ 当数据库定义的顺序和现实中的顺序(如时间顺序)相关时,一般采用上面的方式建立集。冒号用同一级别的两个成员作为端点。在冒号两边可以是相同的成员,表示集中只有一个成员

    image-20210319141456090

    ​ 在给集中添加子集时,可以在该集中任何地方使用逗号操作符。例如,下面的语句产生包含1997年前三个月和后三个月的集:

    {	{[Time].[1997].[Q1].[1] : [Time].[1997].[Q1].[3]},
    	{[Time].[1997].[Q4].[10] : [Time].[1997].[Q4].[12]}    }
    

    ​ 而下面的语句产生包含1997年及其前三个月的集:

    {	 [Time].[1997], 
         {[Time].[1997].[Q1].[1]: [Time].[1997].[Q1].[3]}
     }
    

    image-20210319142439718

    .Members

    ​ 无论用于检索,还是作为更复杂的操作的基础,获得一个维度、层次结构或者级别的成员的集是非常普遍的操作。

    ​ 维度、层次结构或者级别放置在.Members 操作符的左边,可以返回由该元数据范围内所有成员构成的集。

    例如,[CustomcrJ.Members产生包含所有顾客的集,而[ProductJ.[Product Category].Members返回Product,维度中Product Category级别的所有成员。

    例如,查询:

    SELECT
    	{[Customers].Members} ON COLUMNS,
    	{[Product].Members} ON ROWS
    FROM
    	[Sales]  <-- 太慢,只在IDEA中跑出来了 使用 ↓
    
    SELECT
        {[Gender].Members} ON COLUMNS,
    	{[Customers].Members} ON ROWS
    FROM 
    	[Sales]
    

    image-20210319143950616

    ​ 逐列显示 Gender维度的所有成员,并且逐行显示Customers维度的所有成员。当客户端使用.Members(或者其他的元数据函数,这些函数返回与某个元数据要素相关的成员集)

    .Children

    ​ 另外一种非常常用的查询是获得一个成员的子成员。这么做的目的可能是执行一个向下钻取操作,或者为了方便地获得基于一个共同父成员的范围内的成员。MDX 提供.Children函数来完成这个操作。

    下面的查询将选择[Product].[ Drink]成员和它的子成员,并在报表的各行上显示,如图

    SELECT
    	{[Time].[1997].[Q1].Children} ON COLUMNS,
    	{[Product].[Drink],[Product].[Drink].Children} ON ROWS
    FROM
    	[Sales]
    WHERE {[Measures].[Unit Sales]}
    

    image-20210319150429021

    .Descendants

    ​ 为了得到直接子代之下的后代成员,或者更普遍的,为了搜索本层次结构之下的成员,可以使用Descendants()。

    语法

    Descendants (menber [, [level] [,flag]] )

    Descendants()返回member之下与level或者代次相关的成员,并且对于可选参数flag,有很多选项。Flag 的可选值有:

    • SELF
    • BEFORE
    • AFTER
    • SELF_AND_BEFORE
    • SELF_AND_AFTER
    • SELF_BEFORE_AFRER
    • LEAVES

    ​ SELF仅仅指member 以下 level级别上的成员,这是最常用的选项。例如,下面的语句选择1997年的月份

    SELECT 
    {[Product].[Drink],[Product].[Food]} ON COLUMNS,
    Descendants (
        [Time].[Year].[1997],
        [Time].[Month],
        SELF
    	)
    	 ON ROWS
    FROM 
    [Sales]
    WHERE {[Measures].[Store Cost]}
    

    image-20210319151616398

    ​ 因为SELF 很常用,所以如果忽略flag参数,那么默认使用 SELF。例如,即使没有在查询中显式地包含SELF,Descendants ([Time].[Year],[Time].[Month])也会返回2005年的月份列表

    ​ 其他的包含SELF的标志指的是参考级别附近的级别。SELF_AND_BEFORE 意味着返回member 所在级别以及level级别之间的所有成员,也就是包含member在内、从 level级别到member级别的所有成员。例如,下面的语句选择1997年及其所有季度和该年的所有月份,

    SELECT 
    {[Product].[Drink],[Product].[Food]} ON COLUMNS,
    Descendants (
        [Time].[Year].[1997],
        [Time].[Month],
        SELF_AND_BEFORE
    	)
    	 ON ROWS
    FROM 
    	[Sales]
    WHERE {[Measures].[Store Cost]}
    

    image-20210319151959636

    SELF_AND_AFTER意味着返回从参考级别level 到叶级别之间的所有成员。

    SELF_BEFORE_AFTER意味着从给定的成员member开始到下面叶级别之间的整个子树。

    注意,这与Descendants ([Time].[1997])效果相同,因为不使用标志flag 和级别 level参数意味着取回所有后代成员。
    也要注意到可以使用数字而不是级别的引用,来访问特定级别的后代成员或者距离给定成员一定深度的后代成员。

    去除查询结果中的空切片

    在一个多维空间中,数据稀疏现象很常见。

    例如,不是所有的产品都会在任何商店、任何时间段卖给每一位顾客,所以对特定的产品集、时间段和顾客的查询,可能会返回一些在一个或者多个轴上完全为空的切片。

    应该非常确定,没有哪个零售商会12月在夏威夷卖雪铲,但是它们在芝加哥却很难有库存。

    某位用户希望看到空的切片,因为空切片可以告诉他或她自己在某处缺乏行动;但是该用户也可能对这些空切片不感兴趣,并想将其从报表中移除。

    SELECT
    {[Time].[Month].[1],[Time].[Month].[2]} ON COLUMNS,
    {
    [Product].[Food],
    [Product].[Food].Children
    } ON ROWS
    FROM [Sales]
    WHERE {
    [Measures].[Store Cost]
    }
    

    去除空切片需要做的仅仅就是在待移除空切片的轴前面加上 NON EMPTY 关键字。

    在本例中,NON EMPTY的位置是在ON COLUMNS后面的逗号之后,在标识要查询的产品的左大括号“{”之前。先计算查询,在各列所有的数据都得到之后,最后返回至少在一列上有数据的行。

    NON EMPTY可以用在任何轴、维度和元组上。可以将上述查询的行列交换如下:

    SELECT
    {[Time].[Month].[1],[Time].[Month].[2]} ON COLUMNS,
    NON EMPTY {
    [Product].[Food],
    [Product].[Food].Children
    } ON ROWS
    FROM [Sales]
    WHERE {
    [Measures].[Store Cost]
    }
    

    还有其他函数可以用来从查询结果中去除带有空数据的成员,但是NON EMPTY是最适合做这个操作的。

    注释

    为了方便编写程序文档,MDX 中可以使用3种注释语法,这无疑可以适合于很多编程风格(就像其他的编程语言一样,为了调试方便,在MDX中也可以将部分代码注释掉),

    第一种风格

    SELECT // 这是一个注释
    {[Measures].[Store Cost]} on columns,
    {[Product].[Food]} on rows
    FROM 
    [Sales]
    

    第二种风格

    SELECT
    {[Measures].[Store Cost]} on columns,
    /* 这是一个注释
    {[Product].[Food]} on rows
    */
    {[Product].[Food]} on rows
    FROM 
    [Sales]
    

    第三种风格

    SELECT -- 这是一个注释
    {[Measures].[Store Cost]} on columns,
    {[Product].[Food]} on rows
    FROM 
    [Sales]
    

    MDX数据模型 : 元组和集

    元组

    一个元组是来自一个或多个维度的成员的组合,它本质上是个多维成员。

    单个成员是个简单的元组(例如,[Time].[Jun, 2005)。

    当一个元组有多个维度时,对于每个维度,它只能有一个成员来自其中。

    为了组成一个多维的元组,必须使用括号将成员括起来,例如:

    ([Product].[Food],[Time].[Year].[1997])

    一个元组可以代表多维数据集的一个切片,这样多维数据集就被元组中的每个成员分割。一个元组也可以是MDX中独立操作的数据对象。

    使用上述语法可以直接在查询中包含元组。

    SELECT
    {
    ([Time].[1997],[Measures].[Store Cost]),
    ([Time].[Month].[5],[Measures].[Unit Sales])
    } ON COLUMNS,
    {[Product].[Food],[Product].[Drink]} on rows
    FROM [Sales]
    

    image-20210319170253773

    从返回的结果可以看出,本例采用的时间和度量的组合不是很对称。

    但这一点也说明可以随心所欲地控制从查询返回什么样的成员和单元的组合。

    也可以将一个成员放入括号,但是如果元组仅由那一个成员构成,则不一定要那样做。但是下面的元组无效,因为它有两个时间维度。

    ([Product].[Food],[Time].[Month].[5],[Time].[Month].[8])

    也不能构成空的元组。()是无效的元组

    除了通过在代码中显式地组成元组外,还有很多函数返回元组。

    元组的“维度范围”指的是组成该元组的成员的维度的集合。

    对于元组的维度范围而言,维度在元组中出现的顺序很重要。

    所有的维度都可以成为元组的一部分,包括度量维度。

    可以通过括号()组成元组,但是不能用元组构成元组。也就是说,可以按如下方式构建一个元组:

    (

    [Product].[Food],

    [Time].[Month].[5],

    [Time].[Month].[8]

    )

    但是不可以 :

    (

    [Product].[Food],

    ​ (

    ​ [Time].[Month].[5],

    ​ [Time].[Month].[8]

    ​ )

    )

    在计算和查询中,MDX通过元组来区分单元。

    从概念上讲,每个单元由其对应的元组确定,而该元组的成员来自多维数据集的与单元对应的维度(这与电子制表有几分像,其中表1,列B,行22标识一个单元。)

    在一个查询中,成员的有些维度显示在行上,有些显示在列上,有些则显示在页上,其他的放在查询切片器中。

    但是,两个或更多的元组的交集可以构成另一个元组,所以把这些元组全部组合在一起最终就会得到一个单元。

    元组([Product].[Leather Jackets],[Time].[June-2005],[Store].[Fifth Avenue NYC],[Mcasures].[DollarSales])可能完全定义了一个值为13000美元的单元。

    尽管一个元组就是成员的组合,但当该元组在由数字或字符串构成的表达式中应用时,它默认的作用是注明该元组对应的单元的值的来源。

    这一点对于理解MDX某些函数的功能非常重要。

    集是元组的有序集合。一个集可能有不止一个元组,也可能只有一个元组,或者是空的。

    与数学的集合不同,MDX集可能多次包含同样的元组,而排序在MDX集中非常重要。

    尽管集称为“聚集”或者“序列”可能较好,但是眼下坚持使用“集”。

    根据集使用的上下文,它要么是指元组集合,要么是指元组指定的单元的值。

    从语法上讲,有很多方法指定一个集。

    但最普遍的方法可能就是用列举构成集的元组。下面的查询使用两个集,其中行的集是一维的,列的集是二维的。

    SELECT
    {
    ([Time].[1997],[Measures].[Store Cost]),
    ([Time].[Month].[5],[Measures].[Unit Sales])
    } ON COLUMNS,
    {[Product].[Food],[Product].[Drink]} ON ROWS
    FROM [Sales]
    

    任何时候显式列举元组,都要用大括号括起来。

    一些 MDX 操作符和函数也返回集。

    如果集不是由多个元组构成,则使用它们的表达式不需要用大括号括起来,但是因为编程风格的原因,通常还是会用大括号将集表达式括起来。

    虽然单个成员默认是一个一维度的元组,但是一个元组并不等价于只有一个元组的集。就标准MDX而言,下面的两个示例差别较大:

    SELECT
    ([Time].[1997],[Product].[Food]) ON COLUMNS
    FROM [Sales]
    WHERE [Measures].[Unit Sales]
    

    下面的查询在所有的MDX查询中都有效

    SELECT
    {([Time].[1997],[Product].[Food])} ON COLUMNS
    FROM [Sales]
    WHERE [Measures].[Unit Sales]
    

    类似地,碰巧只包含一个元组的集仍被看作一个集。

    所以,即使能确定一个集只包含一个元组,但要在需要使用元组的上下文中(例如,在 WHERE子句中)使用它,还是必须调用MDX函数从该集返回元组。

    集也可以是空的,既可能因为显式的定义(例如,0),也可能是由于某些原因函数返回了一个空集。

    集中的每个元组都有同样的维度范围(即元组的维度及其在元组中的顺序)。下面的语句将会发生错误,因为维度的顺序改变了:

    {
    ([Time].[1997],[Measures].[Unit Sales]),
    ([Measures].[Store Cost],[Time].[Month].[5])
    }
    

    但是,为了满足各种需要,不同的集可以拥有不同的维度和维度顺序。空集没有维度范围。
    除了通过编码显式地创建集,还有很多函数返回集。

    查询

    MDX查询的结果就是从查询的多维数据集转化而来的另一个多维数据集。

    这与标准的SQL查询结果类似,它本质上是另一张表。

    结果多维数据集可以有一个、两个、三个、四个或者更多的轴。

    从技术上讲,一个查询也可能有0个轴,但是它仍然会返回一个单元的值。

    一个结果轴上的每个元组本质上是结果多维数据集的一个成员。

    正如前面所描述的,查询结果的每个轴由许多元组构成,每个元组都有一个或多个维度。

    当多维元组在查询的轴上结束时,维度在元组中的顺序将影响轴上的嵌套顺序。

    列表中第一个维度成为最外面的维度,第二个成为次外面,以次类推,最后一个维度在最里面。例如,假设下面的集在结果的“行”轴上显示:

    SELECT
    ...
    {
    ([Time].[1997],[Product].[Food]),
    ([Time].[1997],[Product].[Drink]),
    ([Time].[2004],[Product].[Non-Consumable]),
    ([Time].[2004],[Product].[Drink])
    } ON ROWS
    ...
    

    在这个示例中,通过用于OLAP的OLE DB或者ADO返回到客户端的数据的预期结果。

    image-20210319175925363

    零轴查询

    SELECT FROM [Sales]

    SELECT FROM [Sales]
    WHERE (
           [Time].[1997],
           [Product].[Drink],
           [Product].[Non-Consumable],
           [Product].[Food]
          )
    

    因为上面两个查询都没有把成员分配到任何(无限制器)轴上,所以认为结果有零轴,并且按照惯例,结果将只是无标号的单元,或者是没有不同的行标题或列标题的单元。

    在当前支持MDX的所有API中,限制器的信息作为查询结果的一部分返回。而是否把结果当作零轴,取决于在切片器信息随单元一起返回时,是否忽略其中传达的维度信息。.

    只有轴的查询

    注意,所有的MDX查询都返回单元。

    但是,如果真正感兴趣的结果不是单元的数据,而是与单元数据或者成员属性值相关的成员,那么很多实用的查询会询问“什么样的成员属于这个集”。

    一个这种形式的查询如“显示占我们的财政收入百分比前十名的顾客”,也将隐式地要求单元值集(但是,由于内部的最优化机制,上面的查询将得不到那些单元值)。

    这与SQL形成鲜明对比,SQL 只返回查询的列。

    更多方法

    CrossJoin

    在许多情况下,如果想要获取两个不同的集的成员(或元组)的交叉组合(即,指定它所有可能的组合),CrossJoin()函数是以这种方式组合两个集的最直接方法。
    语法如下:
    CrossJoin (set1, set2)

    例如,如果想要在列上显示1997年前两个季度的门店销售额和产品销售件数,使用下面的表达式就可以产生这个集;

    SELECT
    CrossJoin(
    	{[Time].[1997].[Q1],[Time].[1997].[Q2]},
     	{[Measures].[Store Sales],[Measures].[Unit Sales]}
    )ON COLUMNS,
    {[Product].[Food],[Product].[Drink]} on rows
    FROM Sales
    

    image-20210319182416094

    CrossJoin()只采用两个集作为输入。如果想输入3个或者更多的集,诸如 Time.Scenario及Product,可以通过嵌套调用CrossJoin()达到目的,如下所示:

    CrossJoin(
       [Measures].[Store Sales]
        CrossJoin(
        [Product].Members,
        [Customers].Members,    
       )
    )
    
    CrossJoin(
        CrossJoin(
         [Time].Members,
         [Customers].Members
     ),
        [Product].Members
    )
    

    注意,这两个调用都产生同样的集,它的维度范围按顺序是Time、Scenario及 Product.而读者可能偏爱某个函数,当这个集较大时,还可能想弄清在自己的 MDX软件内这些函数的性能差异。

    CrossJoin()属于标准 MDX。icrosoft Analysis Services利用*(星号)将上述功能扩展表示成“集的乘法”,即:

    {[Time].Members} * {[Customers].Members} * {[Product].Members}

    这种表示法执行了与 CrossJoin()相同的操作,而且如果不考虑简便与否的话,这种表示法可能更加容易读写。

    CrossJoin)的一个常见用法是把某个维度的单个成员与另一个维度的若干成员组合起来,例如,通过把一个特殊的度量与其他维度的许多元组组合在一起,来创建一个集。

    当在某个计算度量的公式中涉及到统计另一个度量的非空单元的数量时,就需要这个结构。不能使用范围操作符构造多个维度的元组,尽管这个想法看起来可行。

    例如,要表达“1到10号商店的牙膏”这个范围概念,有可能想编写下面的语句 ;

    	{
    	[Product.][Toothpaste],
    	  {[Geography].[Store 1] : [Geography].[Store 10]}
    	}
    

    但相反,实际需要使用CrossJoin()(或者*形式),如下所示:

    CrossJoin(
    {[Product.][Toothpaste]},
     [Geography].[Store 1] : [Geography].[Store 10]
    )
    

    在前面有些CrossJoin()示例中,在语句的表达方式上,没有使用大括号将集括起来,因为那里没必要用大括号。但是,既然函数需要一个集作为参数,那么这里用大括号将单个成员[Toothpaste]括起来,以将元组转化成一个集,确实要好些。

    ================= 未完待续。。。。

    FoodMart 立方体分析

    维度

    Customers

    -- 顾客维度有什么
    SELECT
         country -- 国家
        ,state_province -- 州省
        ,city -- 城市
        ,customer_id -- 客户id
        ,Gender -- 性别
        ,marital_status -- 婚姻状况
        ,education -- 教育
        ,yearly_income -- 年度收入
    from customer
    

    Product

    -- 商品维度有什么
    SELECT p.brand_name				 -- 品牌名称
         , p.product_name			-- 商品名称
         , pc.product_family		-- 大类
         , pc.product_department	-- 小类
         , pc.product_category		-- 种类
         , pc.product_subcategory	-- 范畴
    FROM product p
    inner join product_class pc on p.product_class_id = pc.product_class_id;
    

    指标

    • Unit Sales : 单位产品销售额

    • Store Cost : 存储成本

    • Store Sales : 店销售

    • Sales Count : 销售统计

    • Customer Count : 客户数

    • Promotion Sales : 促销额

    • Profit : 利润

    • Gewinn-Wachstum : 盈利增长

    展开全文
  • MDX语言介绍

    2020-08-21 10:21:11
    MDX语句(MultiDimensionalExpressions)是一种语言,支持多维对象与数据的定义和操作。它可以表达在线分析出来数据卡上的选择、计算和一些元数据定义等操作,并赋予用户表现查询结果的能力。 MDX是由Microsoft,...

    一、什么是MDX

    MDX语句(MultiDimensionalExpressions)是一种语言,支持多维对象与数据的定义和操作。它可以表达在线分析出来数据卡上的选择、计算和一些元数据定义等操作,并赋予用户表现查询结果的能力。
    MDX是由Microsoft,Hyperion等公司研究多维查询表达式,是所有OLAP高级分析所采用的核心查询语言。
    如同SQL查询一样,每个MDX 查询都要求有数据请求(SELECT子句)、起始点(FROM子句)和筛选(WHERE子句)。这些关键字以及其它关键字提供了各种工具,用来从多维数据集析取数据特定部分。MDX还提供了可靠的函数集,用来对所检索的数据进行操作,同时还具有用户定义函数扩展 MDX的能力。

    二、使用方式

    1、MDX查询语句
    查询所需要的数据。
    2、MDX表达式
    定制需要的指标。
    3、MDX脚本
    指定流程由SQL执行生成自定义的效果。

    三、MDX中的相关概念

    1、多维数据集
    2、度量值(量度)
    3、维度
    4、维度的层次结构
    5、维度的级别
    6、成员(Member)
    指的是维度树上的一个节点,这里有一点需要指出,量度也是一个特殊的维度,所以对于普通维度上的 Member可以有几下几种表示方法: [Customer] 或 [Time].[1996] 等,对于特殊的维度——量度而言,也可以表示一个 Member,如: [Measures].[unitsales] 等。
    标识符:[ ]
    7、元组(Tuple)
    是由若干个Members组成,CUBE上的一个子集(不断开的子CUBE),每一个维度上最多只能有一个 Member,对于一个 Tuple而言至少有一个维度,多则不限,顺序无关,同时对于没有列出来的那就表示为默认的 Member。
    标识符:()
    示例:
    a) ([Regin ].[USA])
    b) ([product].[computers],[time].[2008]) 。
    8、集(Set)

    同一维度上若干个 Members的集合,或者是若干个 Tuples的集合,但这里有一个地方需要注意,那就是如果是若干个 Tuple组成的集合是,各个 Tuple里的 Member之间存在着一定的对应关系。集合的表示方法用大括号“ {} ”,所以可能的表示方法为:
    a) {[time].[2008],[time].[2009],[time].[2000]} ,这里 Set是由 同一维度的若干个 Member组成。
    b) {([computer],[usa ]),([mobile],[china])} ,这个 Set是由两个 Tuples组成,这里大家可以看到,在第一个 Tuple当中,第一个 Member是名为 computer的产品,所以后面的 Tuple的第一个 Member也必须是一个产品,所以我们这里看到的是 mobile,第一个 Tuple里第二个 Member是一个国家,所以第二个 Tuple的第二个 Member也必须是一个国家名,依次类推。
    标识符:{ }

    四、基本语法

    一个标准的 MDX查询语句就是由我们前面介绍的 MDX的三个基本对象构成,也就是 Member、 Tuple、 Set。

    1、SELECT SET ON COLUMNS,
    SET ON ROWS
    FROM CUBE
    WHERE TUPLE
    
    • 1
    • 2
    • 3
    • 4
    2、SELECT SET ON 0,
    SET ON 1
    FROM CUBE
    WHERE TUPLE
    
    • 1
    • 2
    • 3
    • 4

    五、简单MDX查询示例

    想象一个简单的带有时间、销售地点和度量3个维度的多维数据集,该多维数据集的名称为销售额(即SALES)。其中度量包括销售额和成本。假如想查看2005年前两个季度马萨诸塞州的销售额与成本,如图所示。

    我们可以通过下面的MDX获得想要的数据:
    SELECT {[MEASURES].[DOLLAR SALES],[MEASURES].[UNIT SALES]} ON COLUMNS,
    {[TIME].[2005].[Q1], [TIME].[2005].[Q2]} ON ROWS
    FROM [SALES]
    WHERE ([CUSTOMER].[MA])

    MDX查询的结果本身是一个网格,本质上是另一个多维数据集。下面将这个简单的查询拆开来仔细研究。
    关键字SELECT后带需要检索内容的子句。

    关键字ON和轴的名称一起使用,以指定数据库的维度显示位置。该示例查询将度量显示为列,将时间段显示为行。

    MDX用大括号{ }引用来自某个特点维度或者多个维度的一组元素。这个简单的查询在其两个轴中的每一个上都只有一个维度(度量维度和时间维度)。元素间用逗号隔开。元素名称用方括号引用,并且不同组成部分之间用点号分隔。

    MDX能够的FROM子句指明用于查询数据的多维数据集。这与SQL中的FROM子句类似。
    WHERE子句指定在列或行(或者其他轴上)不出现的多维数据集其他维度的成员。如果不对某个维度指定一个成员,MDX将使用默认成员。WHERE子句是可选的。

    提示:MDX不是大小写敏感的,可以随心所欲的混用字母大小写。

    六、MDX中的简单函数和操作符

    1、逗号(,)与冒号(:)
    可以通过枚举元素并用逗号来隔开构造一个集,例如上面示例中用到的例子。
    {[TIME].[2005].[Q1], [TIME].[2005].[Q2]}
    该表达式产生一个包含2005年第一季度和第二季度的集。
    冒号用同一级别的两个成员作为端点,来表示这两个端点间的所有成员(与EXCEL中的指定单元格范围的用法类似)。在冒号两边可以是相同的成员,表示集中只有一个成员。例如:
    {[TIME].[2005].[SEP]: [TIME].[2006].[MAR]}
    该表达式表示从2005年9月到2006年3月的所有月份。
    2、.MEMBERS 获取所有成员
    无论用于检索,还是作为更复杂的操作的基础,获得一个维度、层次结构或者级别的成员的集是非常普遍的操作。维度、层次结构或者级别放置在.MEMBERS操作符的左边,可以返回由该元数据范围内所有成员构成的集。
    例如:
    [TIME].[MONTHS].MEMBERS
    该表达式返回时间维度下的月这一级别的所有成员(即所有月份)。
    3、.PREMEMBER获取指定成员的前一个成员
    4、.NEXTMEMBER获取指定成员的后一个成员
    5、使用.CHILDREN获得一个成员的子成员
    另外一个常用的查询时获得一个成员的子成员。这么做的目的可能是执行一个向下钻的操作,或者为了方便的获得基于一个共同父成员的范围内的成员。例如:
    [TIME].[YEARS].[2005].CHILDREN
    该表达式返回2005年的所有孩子(即2005年的所有月份)。
    6、.FIRSTCHILD 获取指定成员的第一个子成员
    7、.LASTCHILD获取指定成员的最后一个子成员

    七、更多基本词汇

    1、DESCENDANTS() 获取一个成员的后代成员。
    直接子代之下的后代成员,可以使用DESCENDANTS()。
    语法:
    DESCENDANTS(MEMBER,LEVEL,FALG)
    返回MEMBER之下与LEVEL相关的成员,并且可选参数FLAG。
    FLAG的可选值有:
    SELF
    BEFORE
    AFTER
    SELF_AND_BEFORE
    SELF_AND_ AFTER
    SELF_ BEFORE _BEFORE
    LEAVES
    SELF仅仅指MEMBER以下LEVEL级别上的成员,这是最常用的选项,如果忽略FLAG参数,那么默认使用SELF。例如:
    DESCENDANTS([TIME].[YEARS].[2005],[TIME].[MONTH])
    该将返回2005年的所有月份。
    SELF_AND_BEFORE将返回MEMBER所在级别已经LEVEL级别之间的所有成员,也就是包含MEMBER在内、从LEVEL级别到MEMBER级别的所有成员。例如:
    DESCENDANTS([TIME].[YEARS].[2005],[TIME].[MONTHS],
    SELF_AND_BEFORE)
    该表达式将返回2005年及该年的所有季度和所有月份。
    2、FILTER() 过滤
    FILTER()函数用来缩减集(过滤),它表示在结果集中只包含那些符合特定标准的元素。FILTER()采用一个集和一个布尔表达式作为它的参数,并且当布尔表达式为真时,返回该集的子集。
    语法:
    FILTER(SET,BOOLEAN-EXPRESSION)
    例如:
    FILTER({[PRODUCT].[PRODUCTCATEGORY].MEMBERS},
    [MEASURES].[DOLLARSALES]>=500)
    该表达式将返回相关美元销售额在500元以上的某类产品构成的集。
    FILTER()可以操作元组构成的任何集,而不仅仅是以个维度的成员构成的集。
    3、ORDER() 排序
    ORDER()用来根据相关数据值给集的元组排序。
    语法:
    ORDER (SET,EXPRESSION,FLAG)
    ORDER()的参数包括一个集、排序标准,还有一个可选的标志,该标志指示排序原则(升序或降序,包含或者忽略元组间的层次关系)。ORDER()返回的集由原来的集的元组构成,但按照新指定的顺序重新排序。
    例如:
    ORDER([PRODUCT].[PRODUCTCATEGORY].MEMBERS},
    [MEASURES].[DOLLARSALES],BDESC)
    该表达式将按销售额对产品进行降序排序(BDESC将忽略层次结构)。
    4、.CURRENTMEMBER 获取当前成员
    语法:
    DIMENSION.CURRENTMEMBER
    返回该维度的当前成员。
    5、.PARENT 获取指定成员的父对象成员
    语法:
    MEMBER.PARENT
    返回对给定成员的父对象成员。
    6、NONEMPTY去除空切片
    在一个多维空间中,数据稀疏现象很常见。MDX中提供了从查询的结果中移除完全为空的切片的方法,那就是使用NONEMPTY关键字。去除空切片需要做的仅仅是在待移除空切片的轴前面加上NONEMPTY关键字。NONEMPTY可以用在任何轴、维度和元组上。
    7、去年同期的引用和计算
    一个经常会用到的计算是查询一年前同一时期的数据,或者上一个季度同一时期和上周同一天的数据。可以使用PARALLELPERIOD()函数。
    语法:
    PARALLELPERIOD(LEVEL,INDEX,MEMBER)
    该函数首先的到级别LEVEL中成员MEMBER的主席,然后从该祖先的兄弟成员中找到编号比该祖先小INDEX的成员(称为姻亲),最后返回该姻亲的后代成员中MEMBER的堂兄弟。
    例如:
    PARALLELPERIOD([YEARS],1,[MAY2006])
    将返回[MAY2005]

    展开全文
  • 多维数据查询OLAP及MDX语言学习整理

    千次阅读 2018-01-16 13:51:38
    他们是一种多维结构,包含原始事实数据、聚合数据,这些数据聚合允许用户快速进行复杂的查询,Mdx语言就应用它更是如鱼得水。 Cube包含两个基本概念:维度和度量 维度(Dimension):维度提供了分类描述,...
  • MDX基本语法: SELECT Axes… (选择要返回的维度和成员)——&amp;amp;gt;轴维度 FROM Cube (源数据集,如SQL的表) WHERE Slicer… (特定维度的限定条件,条件筛选)——&amp;amp;gt;切片器维度 1、...
  • 多维表达式MDX

    千次阅读 2007-06-25 09:58:00
    多维表达式 (MDX) 是用于在 Microsoft SQL Server 2005 Analysis Services (SSAS) 中处理和检索多维数据的查询语言MDX 基于 XML for Analysis (XMLA) 规范,并带有特定于 SQL Server 2005 Analysis Services 的...
  • 一步一步学习MDX语言

    2017-11-17 14:36:03
    Microsoft SQL Server 2005 Analysis Services (SSAS) 允许在多维表达式 (MDX) 语法中使用函数。函数可以在任何有效的 MDX 语句中使用,并且经常用于查询、自定义汇总定义以及其他计算。本节介绍 Analysis Services ...
  • 他们是一种多维结构,包含原始事实数据、聚合数据,这些数据聚合允许用户快速进行复杂的查询,Mdx语言就应用它更是如鱼得水。 Cube包含两个基本概念:维度和度量 维度(Dimension):维度提供了分类描述,表示...
  •  MDX是一种结构化查询语言,它比SQL查询语言更复杂,因为MDX是面向多维数据模型进行数据检索用来支持复杂的商业环境数据验证。MDX支持两种不同的模式,一是表达式语言:定义和操作Analysis Service 对象和数据以...
  • 多维数据查询MDX教程(全)

    热门讨论 2010-11-22 13:31:24
    MDX 语言参考 MDX 语法约定 MDX 语句参考 MDX 脚本编写语句 MDX 数据定义语句 MDX 数据操作语句 MDX 运算符参考 --(注释) -(排除) -(负) -(减) *(叉积) *(乘) /(除) ^(幂) /*...*/(注释) //(注释...
  • 多维表达式 (MDX) 是用于在 Microsoft SQL Server Analysis Services (SSAS) 中处理和检索多维数据的查询语言. MDX 基于 XML for Analysis (XMLA) 规范, 并带有特定于 SQL Server 2005 Analysis Services 的扩展. ...
  • 多维表达式 (MDX) 是用于在 Microsoft SQL Server Analysis Services (SSAS) 中处理和检索多维数据的查询语言. MDX 基于 XML for Analysis (XMLA) 规范, 并带有特定于 SQL Server 2005 Analysis Services 的扩展. ...
  • #####概述 1. MDX(Multidimensional Expression)支持多维对象和数据的定义和操作。不是SQL的拓展。 2. MDX查询都要求有se...
  • MDX 的全称是 Mutil Dimensional Expressions ,是由 Microsoft , Hyperion 等公司研究多维查询表达式,是所有 OLAP 高级分析所采用的核心查询语言MDX 可以用来进行以下操作: 1. calculated members ...
  • MDX的全称是Mutil Dimensional Expressions ,是由 Microsoft ,Hyperion 等公司研究多维查询表达式,是所有OLAP 高级分析所采用的核心查询语言MDX 可以用来进行以下操作: 1.calculated members (计算
  • 多维表达式 (MDX) 是一种功能完备、基于语句的脚本语言,用于定义、使用以及从 Microsoft SQL Server 2005 Analysis Services (SSAS) 中的多维对象中检索数据。MDX 提供以下几种语言功能:用于创建、删除以及使用...
  • 多维查询表达式--MDX教程什么是 MDXMDX 的全称是 Mutil Dimensional Expressions ,是由 Microsoft , Hyperion 等公司研究多维查询表达式,是所有 OLAP 高级分析所采用的核心查询语言MDX 可以用来进行以下操作:1...
  • SSAS中MDX语言之二

    千次阅读 2017-10-23 15:55:19
    创建查询的过程:SQL编写1个或多个表的查询,MDX编写对一个多维数据集的查询 Select子句:SQL定义查询的列布局,MDX定义几个轴维度 Where子句:SQL定义查询的行布局,筛选查询返回的数据,MDX将数据限定于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 943
精华内容 377
关键字:

mdx多维语言