分享

通过MDX改变多维数据集和维度环境

 梅兰竹^_^ 2010-07-26
  
 与SQL一样,MDX提供了数据操作语言(Data Manipulation Language,DML)和数据定义语言(Data Description Language,DDL)。使用DDL语句可以在客户端应用中改变既定的多维数据集的环境。无论多维数据集源是什么,都可以对用户会话进行如下操作:
● 改变维度的默认成员
● 更新单元数据和维度成员
  如果维度允许执行回写操作,则还可以
● 创建一个新的成员
● 删除一个成员
● 在层次结构中移动成员
● 更新与成员相关的自定义成员公式或成员属性
  如果多维数据集允许写回,则还能更新其中的数据单元,可以通过编程的方法,也可以使用UPDATE CUBE语句。
  通过这些命令,可以创建诸如预算和预测等应用,在这些应用中用户在无须授予管理权限的情况下就可以访问多维数据集,通常的方法是使用旧的Decision Support Object(DSO)或新的 Analysis Management Object(AMO)来更新数据库。
  执行每条命令之后,数据库以及连接到其上的会话都会立即看到对维度结构所做的修改,并且在该维度之下的表格也会立即更新。为此,系统提供了一定数量的协作构造与分析。
  注意,在一个回写维度上创建新的成员与创建一个新的计算成员不同,更新成员也不等同于改变计算成员的定义。这些操作都会实际地修改底层的维度表格,从而导致结果对连接到其多维数据集的所有用户可见,而计算成员不会存在维度表格中,它仅存在于用户自己的会话中。对协作应用而言,计算成员与自定义成员公式之间的解析顺序与执行顺序的差别可能非常大,我们将在第12章中讨论这些问题。
11.1  在会话中改变维度的默认成员
  每个多维数据集中的每个维度都有一个默认成员,这是当查询中或Dimension.DefaultMember方法中没有引用维度时选中的成员。这个默认成员是由DBA或数据库设计者选择的,可能针对整个维度,也可能针对用户的登录角色。但是,也可以在会话的过程中使用MDX改变这个默认成员。
  更改默认成员的一般语法为:
     ALTER CUBE Cube
         UPDATE DIMENSION Dimension, DEFAULT_MEMBER = 'MDX Rule'
  MDX规则(rule)可以是任何能够产生该维度中单独一个成员的合法MDX表达式,它可能是一个成员的名字,还可能是从一个命名集中选择一项而获得的结果,或者是一个外部函数的结果。但无论是什么,它总是立即进行计算。如果是一个依赖于变化数据的表达式,则需要根据数据的修改重新进行估值。
  例如,假设该规则是‘Tail([Time].[Day].Members,1).Item (0).Item(0)’,它将会选择在时间维度中定义的最后一天(.Item(0).Item(0)。它从集选取的元组中选择成员,在AS2005中可以忽略)。会话期间时间维度的增量更新可能会引入一个新的最后一天,而且能够反映在元数据之中,但是默认成员只有在ALTER CUBE语句再次运行之时才会改变。假设您有一个外部函数来返回所使用的时间成员的名字,又假设规则是‘StringToSet (ExternalDayNameFunction()).Item(0).Item(0)’,那么该规则将会在ALTER CUBE语句运行之时进行求值,并且每次运行都会重新进行求值,默认成员只有在ALTER CUBE语句再次运行时才会发生改变。
  在AS2005中,维度可以有许多层次结构:属性层次结构、用户层次结构和自然层次结构。每一个层次结构都有其自己独立的默认值,并且可以在不影响其他层次结构的前提下进行修改。例如,我们可以为[Customer] .[Martial Status]和[Customer].[Gender]设置单独的默认成员。
  更进一步,在子多维数据集中创建的默认成员(也就是在CREATE SUBCUBE语句发出之后才创建的默认成员)将会在子多维数据集的上下文中生存。如果删除了该子多维数据集,则会恢复原先的默认成员。
11.2  维度回写操作
  如果多维数据集包含允许回写的维度,就可以使用下面的Microsoft MDX命令来操作这些维度。这些命令都是立即生效的,不管会话的transaction isolation mode是否有效;同时它们还是立即提交的,这与UPDATE CUBE和为了能在服务器生效而要求OLE DB和ADO按序提交的单元回写操作不同。尽管可以具体划分为ALTER CUBE语句,它们还是会影响出现在每个多维数据集中的该维度,因此,它们可能一次影响多个多维数据集。
  在AS2000中可以用于普通维度的一些命令在AS2005可能只能应用于父子维度,或者有了更多的使用限制。
  另外,可写入的维度也存在一些限制:例如,层次结构不能有离散集,需要拥有源表格的写权限,表格不能有auto-increment属性,以及另外一些类似的条件。该信息是从数据源获取的并且保存在数据源视图中。
11.2.1  创建新成员
  我们可以使用ALTER CUBE CREATE DIMENSION MEMBER语句在父子维度中创建一个新成员,该语句的常规语法如下:
     ALTER CUBE Cube
         CREATE DIMENSION MEMBER [ParentUniqueName.]MemberName
         , KEY='KeyValue'
         [ PropertyName = 'PropertyValue' [, PropertyName = 'PropertyValue'
     . . . ]]
  该命令的结果是新的行实际上会进入到底层维度表中。
  属性名是诸如[Manager Name]或[Reporting Units]等数据库定义的成员属性,而不是诸如FORMAT_STRING等OLE DB成员属性。
  例如,假设有一个可写入的父子维度,那么下面的操作将会在[HumanResources]成员下添加一个新的[Family Assistance]成员:
     ALTER CUBE IntegratedReporting
     CREATE DIMENSION MEMBER [Accounts].[Net Cash].[Expenses].[Human
     Resources].[Family Assistance]
     , KEY='175'
     , [RollupColumn] = '+'
11.2.2  在维度中移动成员
  如果成员已经存在,但是由于某种原因而需要移动,则可以使用ALTER CUBE MOVE DIMENSION MEMBER命令来完成这个动作。该命令的常规语法是:
     ALTER CUBE Cube
       MOVE DIMENSION MEMBER MemberUniqueName
     [, SKIPPED_LEVELS = '<value>'] [WITH DESCENDANTS]
       UNDER ParentUniqueName
  如果指定了WITH DESCENDANTS子句,那么从该成员开始直到所有叶子的整棵子树都被会移到新的父亲之下;否则,将只有请求的成员才会被移动,并且成员的孩子将会成为成员原先父亲的孩子(如果被移走的成员原来是最顶层的成员,那么该成员的孩子将成为新的根)。该操作对底层维度表格的效果比较简单,只是相应地改变定义该成员的行之父键列的值,也有可能改变定义其直接孩子的行之父键列的值,而新的父键将是在MemberUniqueName中列出的成员。如果使用了SKIPPED_LEVELS子句,那么该成员会被有效地放置到父成员SKIPPED_LEVELS层次步之下,使得它可以出现在从父亲或根算起的更深层次级别的成员的元数据请求中。
  注意,该方法可能并不总是一种使成员成为根成员的好方法。如果维度中没有数据库定义的all级别,那么该成员就无法成为任何成员的孩子成员或者根成员。当然,您可以把成员移动到某个空成员之下然后删除这个空成员,通过这种方法来避开这个问题。
  AS2005对一个维度内成员的可能移动施加了一些限制:如果维度是一个父子维度,则成员可以移动到All级别之外的任何级别,而在“常规维度”中,成员只可以在同一级别内进行移动。因此,举例来说,一个City就永远不会成为一个State。
11.2.3  删除成员
  您可以使用ALTER CUBE DROP MEMBER命令从维度中删除一个成员。该命令的通用语法如下:
     ALTER CUBE Cube
           DROP DIMENSION MEMBER MemberUniqueName
           [WITH DESCENDANTS]
  该命令的作用是删除成员及其在维度表中所对应的行。如果指定了WITH DESCENDANTS子句,那么所有的子孙(以及它们对应的维度表中的行)也会同时被删除。如果省略了WITH DESCENDANTS子句,那么该成员的孩子将成为其父亲的孩子。如果被删除的成员是一个根成员并且忽略了WITH DESCENDANTS,则其孩子将成为新的根成员。
  如果要删除一个计算成员,则可以使用如下命令:
     ALTER CUBE Cube
           DROP CALCULATED MEMBER MemberUniqueName
11.2.4  更新成员定义
  您还可以使用ALTER CUBE UPDATE DIMENSION MEMBER命令来更新成员定义的某些内容。通过该命令,可以改变与成员相关的自定义成员公式,也可以修改一个或多个属性值。该命令的常规语法如下:
     ALTER CUBE Cube
           UPDATE DIMENSION MEMBER MemberUniqueName
     [ AS 'MDXExpression' ] [ , Property = 'Value' [, Property = '<value>' .
     . . ]]
  或者简单一点(没有MDXExpression):
     ALTER CUBE Cube
           UPDATE DIMENSION MEMBER MemberUniqueName
           Property = 'Value' [ , Property = 'Value' . . . ]
  自定义成员公式(或)成员属性值会在OLAP数据库中更新,同时也会在底层维度表中更新。
  例如,下面的代码片段将会把与成员相关的汇总运算符改变成减运算符:
     ALTER CUBE IntegratedReporting
     UPDATE DIMENSION MEMBER [Accounts].[Net Cash].[Expenses].[Human
     Resources].[Family Assistance]
       , [RollupColumn] = '-'
  注意:
  该命令不会修改计算成员的公式。如果确实需要那样做,需要删除该计算成员,然后再次进行创建。
11.3  刷新单元数据与维度成员
  在客户端会话过程中,有可能出现数据需要在服务器进行更新的情况。这些更新可能包含新成员的出现、单元数据的改变、成员属性值的改变,在某些情况下,还可能包含成员删除与重命名。通常来说,在一段时间之后,客户端将会检测到这些改变并开始为新的查询提供新的或修改过的成员和数据。但是,根据连接设置的不同,可能会需要很长时间才能完成这些检测工作。客户端很有可能会使用REFRESH CUBE命令来刷新其缓冲数据。刷新多维数据集的常规语法如下:
     REFRESH CUBE CubeName
  例如,下面的命令将会刷新Sales多维数据集:
     REFRESH CUBE [Sales]
  注意,使用该命令一次只可以更新一个多维数据集。另外,虽然维度的成员可能已经被改变,但在Sales多维数据集中定义的任何命名集都不会被更新。
  当客户端连接到一个本地多维数据集文件而不是一个基于服务器的多维数据集时,REFRESH CUBE命令将会导致多维数据集的内容通过其定义与表格进行重建(本地多维数据集文件将在第17章中讨论。)
11.4  把数据写回多维数据集
  有两种方法可以把数据写回到多维数据集中(假设该多维数据集允许写操作)。第一种方法(标准OLE DB for OLAP支持)是通过数据结构,另外一种方法是使用Microsoft的 UPDATE CUBE语句。这两种方法我们都会展开讨论,但可能会对UPDATE CUBE语句讨论得更加深入一点。另外值得一提的是,UPDATE CUBE语句还可以用来代替标准写回功能。
11.4.1  标准单元写回
  标准单元写回功能主要是通过编程的方法改变一个已从数据库获得的单元的值,这就意味着已经执行过一次产生该单元的查询操作。在OLE DB for OLAP中,当请求查询的结果将其插入到一个范围行集中时(通过IMDRangeRowset:GetRangeRowset),就可以通过获取范围行集上的IRowsetChange接口来更新单元,还可以像更改关系数据库中的可更新字段那样改变单元的值。该操作的详细介绍包含在OLE DB for OLAP文档中,如果需要,您可以进行翻阅。使用ADOMD,在把一个查询的结果获取到一个Cellset对象中后,就可以通过简单地给单元赋予一个新值来更新一个单元的值。关于Microsoft Analysis Services,有两个重要的细节值得一提:
● 一个多维数据集中只有叶级别单元可以通过写回到数据结构的方法来进行更新,这也就意味着计算成员的任何单元都不可更新。如果单元不是一个常规多维数据集中的叶单元,也无法被写回。
● 只有Value列(或者Cellset对象的ADOMD .Value属性)可以被写回,Formatted_Value和其他单元属性都无法写回。
  在ADOMD中,下面的VB代码片段可以对单元进行更新操作:
     Dim ResultCS As ADOMD.CellSet
     Dim cmd AS ADODB.Command
    
     Set ResultCS = cmd.Execute ("SELECT...")
    
     ResultCS (1, 1) = 45 ' update cell 1,1 with the value 45
11.4.2  提交与回滚
  注意,更新实际数据库中的单元数据总会涉及到编程以及MDX的使用。单元更新是通过OLE DB事务来控制的,当您运用本节中介绍的技术来更新单元数据时,首先要从更新会话缓冲中保存的数据开始。通过本节中的各种技术,您可以执行各种what-if?计算(无法删除一个特殊更新的结果,如果想要回滚一个特殊的条件计算,则需要记忆到底进行过何种改变,然后应用与其相反的操作。但是,您可以回滚所有未提交的改变)。如果想要更新共享数据库,使得数据库保持修改的结果并且让所有用户都看到您的修改,就需要通过编程的方式提交修改。为了提交对连接所做的更新操作,在OLE DB中需要使用IRowsetUpdate:Update()方法,而在ADOMD中则需要使用ADODB的Connection.CommitTrans方法。类似的,您还可以使用IRowsetUpdate:Undo() 和Connection.RollbackTrans来撤消修改。
  在Microsoft Analysis Services中提交事务时,所有改变单元的计算delta值都将被写到回写表中。如果一个单元被改变的次数超过一次,则只有一行会被写入到回写表中,这一行会包含所有delta值的和。
11.4.3  使用UPDATE CUBE
  Microsoft的UPDATE CUBE语句扩展了MDX,在标准单元更新机制的基础之上提供了一组增强措施。从功能上来讲,它使得聚合单元可以更新并且提供了一组选项来把数据分配到叶级别单元之上。同时,UPDATE CUBE还提供了一个基于语言的接口,这使得任务的解释可以在低级别编程之前进行,而后者要求打开一个查询并且通过编程将新数据放入查询返回的单元数据结构。对于标准的写回机制,与计算成员相关的单元无法更新,与单元相关的度量也必须使用SUM聚合。
  注意:
  更新一个与基于级别的维度中成员相关的单元将会导致相关的叶单元通过4个功能函数之一进行更新。即使是父子维度中的父亲也是这样,此时非叶数据可能会直接来自于底层的事实表。但是,在AS2000中通过.DataMember函数支持的仅向父亲进行写入的功能在AS2005中不再支持。
  当Analysis Services执行一条UPDATE CUBE语句时,首先会决定将会被更新影响的叶级别单元的集,然后为其中单元计算新的值和delta值。这样的结果是,更新单元将会拥有由UPDATE CUBE命令指定的值,但是当多个单元对聚合单元有影响时,这些单元中的值可能会以各种方式产生变化。我们将会在讲述语法的课程中描述具体的分配方法。
  UPDATE CUBE命令的常规语法如下:
     UPDATE [CUBE] CubeName
     SET tuple [.VALUE] = New_aggregate_value
     [ USE_EQUAL_ALLOCATION |
       USE_EQUAL_INCREMENT |
     USE_WEIGHTED_ALLOCATION [BY Weight_value_expression ] |
     USE_WEIGHTED_INCREMENT [BY Weight_value_expression ]
     ]
  元组表达式指定的单元可能是多维度空间中的任何单元(也就是说,它并不必为叶单元)。但是,该单元必须使用Sum聚合函数来进行聚合操作并且一定不能包含元组中用于标识单元的计算成员。
  如果多维数据集中的某个维度没有在元组中列出任何成员,则使用该维度的默认成员。注意,在New_aggregate_value或 weight_value_expression两边并没有引号。
  有4种可用的不同分配方法:
  (1) USE_EQUAL_ALLOCATION。每个对更新单元有贡献的叶级别单元都会被赋予相同的值。New leaf cell value =New_aggregate_value/Count (叶单元与聚合单元相关)。
  (2) USE_EQUAL_INCREMENT。每个对更新单元有贡献的叶级别单元都改变相同的增量:New leaf cell value= Original leaf cell value + (New_aggregate_value – Original aggregate value)/Count(叶单元与聚合单元相关)。
  (3) USE_WEIGHTED_ALLOCATION。每个对更新单元有贡献的叶级别单元都会被赋予更新单元的一部分(权值)。New leaf cell value = New_aggregate_value * Weight_value_ expression。
  (4) USE_WEIGHTED_INCREMENT。每个对更新单元产生影响的原子单元都会发生改变,改变的值是更新单元增量(正或负)的一部分(权值)。New leaf cell value = Original leaf cell value + (New_aggregate_value - Original aggregate value) * Weight_value_expression。
  如果没有提供Weight_value_expression,则在默认情况下将会为其赋值下面的表达式(原始叶对原始聚合的部分贡献):
     Original leaf cell value/Original aggregate cell value
  无论如何,您都应该确保每个单元的weight_value_expression在0~1之间取值。如果所有叶级别单元的weight_value_expression值的和为1,那么在UPDATE CUBE指令执行之后叶单元的和将是New_aggregate_value。但是,如果所有叶级别单元的weight_value_expression值的和不是1,那么UPDATE CUBE指令的结果将是被指定单元拥有一个按比例比New_aggregate_value大或小的值。通常来说,您可以使用一个weight_value_expression来为一个或多个维度中多级别上的一些度量生成比率值,以此保证其权值之和为1。如果参与考虑的维度不止一个,则更要加倍小心。例如,假设您想要在不同商店之间分配销售目标,则可以使用前一年中每个商店对总体销售额的贡献比率(参见第3章),作为一个weight_value_expression:
     ([Measures].[Sales], Parallelperiod([Time].[Year],1)) /
     ([Measures].[Sales], Parallelperiod([Time].[Year],1), [All Geography])
  这个小数值是每个[Geography].currentmember对总和的“边缘贡献”。
  假设您想要根据产品来分配销售目标,则可以使用:
     ([Measures].[Sales], Parallelperiod([Time].[Year],1)) /
     ([Measures].[Sales], Parallelperiod([Time].[Year],1), [All Products])
  但是如果您想要根据商店和产品来分配销售目标,则必须使用商店和产品的“联合贡献”,方法如下:
     ([Measures].[Sales], Parallelperiod([Time].[Year],1)) /
     ([Measures].[Sales], Parallelperiod([Time].[Year],1), [All Geography],
     [All Products])
  注意,您不能简单地将两个比率相乘来获得weight_value_expression:
     ([Measures].[Sales], Parallelperiod([Time].[Year],1)) /
     ([Measures].[Sales], Parallelperiod([Time].[Year],1), [All Products]))
     *
     ([Measures].[Sales], Parallelperiod([Time].[Year],1))/
     ([Measures].[Sales], Parallelperiod([Time].[Year],1), [All Geography]))
  通过这种方法确实可以获得一个weight_value_expression,但其在所有叶级别上的和通常不是1,而通常来说这个和应该为1。这是因为从统计学上来讲,商店与产品通常是相关的(某些产品会在某些特定的商店/城市/国家中相对地卖出更多),这也就意味着是“联合缘分布”不是“边缘分布”的乘积(您是否还记得,两个事件的“联合可能性”可以从两个“单独可能性”的乘积获得当且仅当这两个是独立不相关的,而通常来说事情并不是这样的……如果OLAP维度是独立的,那么多维度解析就毫无用处了)。
  另外还要记住,weight_value_expression中的计算可以被单元计算、自定义成员公式和所有其他执行表达式时可用的计算所影响。USE_EQUAL_ALLOCATION和USE_EQUAL_INCREMENT方法保证每个相关的叶单元最终都会采用某个值。如果一些单元在UPDATE CUBE命令之前是空的,那么在该命令之后,它们也将会有合适的数据值;在命令执行之前就包含数据的单元则会进行相应的调整。
  注意:
  因为USE_EQUAL_ALLOCATION 和 USE_EQUAL_INCREMENT最终会给每个与聚合单元相关的叶级别单元都赋予一个数据值,所以对某个拥有许多相关叶单元的单元进行赋值可能会消耗大量的内存并且占用很长的时间。
  USE_WEIGHTED_ALLOCATION 和 USE_WEIGHTED_INCREMENT方法对已经拥有数据的单元增加数据值。除非所有与聚合单元相关的单元都为空,否则它们不会为空的相关叶级别单元创建新的单元。如果出现这种情况,与聚合单元相关的第一个单元(与数据库中第一个叶子孙相关的单元会在每个维度上进行排序)会被赋予整个New_aggregate_value。
  由于不同的目的,在创建和预测应用中,每种分配方法都可能是非常有用的。例如,当叶级别单元已经为聚合单元贡献了不同的数量时,USE_EQUAL_INCREMENT保留单元之间的绝对区别(尽管将空单元变成了非空单元),而USE_WEIGHTED_INCREMENT则可以用来维持其比例区别却又不会为空单元赋值。
  例如,下面的语句更新了与Q2-2002 和 Austria相关的month级别、store级别和Provision-VAT合计单元,根据相关store-month估计销售额的比例来增加当前值:
     UPDATE CUBE [Transfer Budget]
     SET (
         [Time].[Q2-2002]
     , [Operating Unit].[Austria]
     , [Account].[Provision-VAT]
     ) = 65000
     USE_WEIGHTED_INCREMENT BY
     [Account].[Est Sales]
     / ([Operating Unit].[Austria], [Time].[Q2-2002], [Account]. [Est
     Sales])
  如果[Account].[Provision-VAT]成员本身是一个父亲成员,那么前面的表达式还会回写到它的每一个叶级别子孙。
11.5  小结
  本章所讲述的命令对于数字应用来说是非常重要的。特别地,CREATE CUBE和 ALTER CUBE UPDATE DIMENSION的虚多维数据集版本可以被任何应用程序用来调整DBA提供的多维数据集和维度。其他所介绍的命令对于交互预算与协作分析应用也至关重要。这些命令对第1章中给出的查询和计算提供了补充,在第12章中,我们将介绍AS2005(以及AS2000)中可用的不同类型计算。
  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多