数据库计算
Essbase中单元格的数据可以是外部输入或计算而得,单元格因而分为输入单元格和计算单元格。计算单元格的计算方法可以通过大纲中维度成员的合并计算符和公式脚本定义,此称为大纲计算定义。
例1:张大明家在上海市区和浦东各有一套房,1月5日时张大明收到市区房子的水费和电费账单,然后缴付;张大明的妻子王翠花同时也收到并缴付了浦东房子的账单。两地的水电单价和用量均不一样。
在HomeFinancial应用程序中,对应的单元格录入数据如下表的数据。表中,灰底的单元格是输入单元格,其中的数据是手工录入;而公共事业费,作为父级成员应由其子代成员作合并计算,所以对应表中黑底的单元格就是计算单元格。
Essbase中子代成员合并到父级成员的计算可以通过合并计算符设置。在维库编辑HomeFinancial应用程序。选中维度结构中任何非1代成员,都有一项【Consolidation】属性,这就是合并计算符。双击此属性进行编辑,如下图,在下拉列表中有7种合并计算符供选择,下表列出了这些计算符的含义。创建成员时,默认的合并计算符是加法“+”。
在例1中,公共事业费需要按如下公式进行合并:
公共事业费 = 电单价 × 电用量 + 水单价 × 水用量
那么是否将公共事业费子成员的合并计算符改成下图设置就够了呢?图中成员名称后是合并计算符。
此思路是对的,但做法在Essbase中行不通。原因是Essbase中同级成员并非按数学中先乘除后加减的顺序计算,而是单纯按照成员排序顺序计算。如果按图中那样,公共事业费的计算就变成了:
公共事业费 = (电单价 × 电用量 + 水单价) × 水用量
要纠正这个错误有两种方法。其一是在维度结构上做文章,按下图重新设计维度结构,得到正确的计算顺序如下:
第二种方法是使用成员公式。通过成员公式可以编写脚本定义计算,成员公式会覆盖子代成员的合并计算。而且Essbase提供了丰富的计算函数和完善的脚本语法,在成员公式中能实现各种复杂的计算。
在维度结构中选择公共事业费成员,修改它的【Member Formula(BSO)】属性,在公式编辑器中输入脚本:
= "水单价" * "水用量" + "电单价" * "电用量";
如果要编写复杂的脚本,推荐使用EAS Console。EAS Console中的公式编辑器更强大,可以提示计算函数和运算符,可以帮助验证脚本语法。Essbase的计算函数和语法可参看官方手册。
有了成员公式,子代成员的合并计算符就没有意义了。出于严谨性考虑,可以将子代成员的合并计算符设为“~”,即子成员不参与合并计算。
回到例1最初的那个表格,横轴和纵轴分别是两个维度,仔细观察表中的计算单元格,会发现存在两个疑问。
第一个疑问,表中两个维度,代表了两种计算方向,这两种方向的计算结果是不一致的。具体来说,最右下角的单元格,代表的是整个家庭公共事业费的合计。如按箭头方向①,即沿Account维度计算,根据成员公式,结果是584.5;反之,按箭头方向②,即沿Home维度计算,根据合并计算符,结果是300.5。
显然第二种计算方向是正确的,那么如何让Essbase按我们希望的方式计算呢?答案是控制Essbase的计算顺序。就是要先计算Account维度,得到表中最下面一行单元格的数据,然后计算Home维度,得到表中最右边一列单元格的数据。后计算的结果会覆盖前面计算的结果,即是说会以300.5作为右下角单元格的最终计算结果。Essbase根据如下条件判断维度间的计算顺序。
- 如果大纲中同时包含Account和Time两种类型的维度,且Account维中使用到成员公式,计算顺序为:
- Account维度
- Time维度
- 密集维度,根据在大纲中排序计算
- 稀疏维度,根据在大纲中排序计算
- 其他情况下,计算顺序为:
- 密集维度,根据在大纲中排序计算
- 稀疏维度,根据在大纲中排序计算
因此,维度的存储类型和在大纲中的排序是控制计算顺序的两个重要手段。如HomeFinancial按照Account > Year > Home > Scenario的顺序计算,这样就能保证产生正确的计算结果。如果不清楚数据的计算顺序,可以在执行计算命令后,从Essbase的日志文件中查看。
此外,若要改变维度中个别成员的计算顺序。比如需要公共事业费在Home维度后计算,即需要表格右下角单元格的计算结果是584.5。那么可以启用公共事业费的【Two Pass Calculation】属性。此属性表明成员需要二次计算,Essbase会在按正常顺序计算一遍后,再用公共事业费的成员公式对相关单元格进行第二次计算。
第二个疑问,是电单价和水单价。按Home维度上的计算方法,使用加分“+”做合并计算,计算结果在父级成员上是无意义的。我们已经将电单价和水单价的合并计算符置为“~”,使之不在Account维度上进行合并计算,那么如何让它们不在其他维度上进行合并呢?实际上,这里想要说明的是合并计算符“~”与“^”的区别,因为这两个计算符常让人困惑和混淆。这个例子中,要让电单价和水单价在Home、Year、Scenario上都不执行合并计算,需要将合并计算符设成“^”,如下图。
改成“^”后,电单价和水单价相关单元格在计算过程中不会产生任何合并计算值。只有使用公式脚本或输入值才能向这些单元格写入数据。
除了记录日常收支流水外,我们还要为HomeFinancial加入计算现余额的功能。因此在Account维度的现金流层次下加入了4个成员。
- 期初现金:某一时期开始的现金量;
- 净收入:总收入减总支出;
- 调整:当发现收支跟现金余额对不上时,用于调整;
- 期末现金:某一时期最后的现金量;
例2:下表记录的是张大明在2013年Q1季度的现金流。
在1月1日时张大明有现金500000元,整个1月份他花了10000元,赚了30000元,则净收入有20000元。1月31日结束时他应该有现金520000元,但由于漏记,或者银行交易产生的手续费,张大明发现实际的金额是519980元,于是补录了20元的调整项。所以有如下等式:
净收入 = 收入 – 支出
期末现金 = 期初现金 + 净收入 + 调整
要在Essbase中实现净收入和期末现金的计算,可以使用成员公式。在维库中编辑净收入的成员公式属性,输入脚本:
= "收入" - "支出";
编辑期末现金的成员公式属性,输入脚本:
= "期初现金" + "净收入" + "调整";
到1月结束时张大明所拥有的现金,同时也就是2月最初所拥有的现金。于是又有如下等式:
期初现金 = 上期的期末现金
将期初现金的成员公式修改为:
IF(NOT @ISMBR("1月1日"))
"期初现金"=@PRIOR("期末现金",1);
ENDIF;
此脚本要求我们在1月1日输入期初现金,之后每一时期的期初现金都等于上一时期的期末现金。
定义了3个成员的公式后,接着要讨论一下这3个成员的计算顺序问题。前面我们使用例1来说明维度间的计算顺序,即同一类型的维度,计算顺序是由它们在大纲中的排序顺序决定的。这一规则也同样适用于同一维度中成员间的计算顺序。在同一维度的成员间,Essbase按照由低级到高级,由前到后的顺序计算。所以现金流这部分成员的计算顺序如下图。
下表用箭头标示了单元格的计算路径。
按照这样的计算路径,期初现金的成员公式会引用到晚于它计算的期末现金,从而产生错误的计算结果。例如当计算2月的期初现金时,1月的期末现金还未计算,结果得到空值。
将引用成员置于被引用成员之前,造成计算顺序错误的现象称为“前置引用”。要解决此问题,方法是让期末现金和期初现金一起计算,修改期初现金的公式脚本为:
IF(NOT @ISMBR("1月1日"))
"期初现金"=@PRIOR("期末现金",1);
ENDIF;
"净收入" = "收入" - "支出";
"期末现金" = "期初现金" + "净收入" + "调整";
然后移除净收入和期末现金的成员公式。依此计算公式,当1月期初现金计算时,1月的净收入和期末现金同时被计算。那么在计算2月期初现金时,就可以得到正确的计算结果。
接着计算2月和3月的现金流。在Q1季度,期初现金应该是1月的期初现金,期末现金应该是3月份的期末现金,净收入和调整是3个月的合计。同理,整个2013年,期初现金是Q1的期初现金,期末现金是Q4的期末现金,净收入和调整是4个季度的合计。
可见,期初现金和期末现金在Year维度上采用了一种特殊的合并方式——分别取第一个子成员值和最后一个子成员值。在现实应用场景中,常常会碰到与时间相关的计算,如同比、环比、累计等。Essbase提供了大量有关Time类型维的计算函数和方法。本例中,除了使用成员公式,可以使用时间平衡(Time Balance)计算实现期初和期末计算。时间平衡计算要求数据库中必须含有Time类型维度,且仅能用在Account类型维度上使用。时间平衡计算不会影响Time类型外其他维度的合并方式。时间平衡有3种计算,含义如下表。
在维库中,将期初现金的【Time Balance】属性设为First;将期末现金的【Time Balance】属性设为Last。
时间平衡计算还有一个属性【Skip Value】,此属性控制是否要忽略空值Missing或零值。比如现金流是从2月开始,1月的期初现金是空值。如果期初现金的【Skip Value】属性是None,不忽略空值和零值,则Q1的期初现金会是1月的空值;如果是Missing,则计算Q1的期初现金时会忽略1月的空值,取2月的值。
在有了大纲计算后,每次录入和修改数据,Essbase是不会自动按合并计算符和成员公式进行计算的。必须执行计算命令,Essbase才会计算相关单元格。计算命令可写在计算脚本中,计算脚本可精确控制计算范围和顺序,还可覆盖大纲计算。可以为数据库创建多个计算脚本,执行不同的计算脚本以实现不同的计算。每个数据库都有一个默认计算脚本。
在EAS Console中,右击HomeFinancial下的y2013数据库,菜单中选择【设置】>【默认计算】。可看到在默认计算脚本中,使用了CALC ALL语句计算整个数据库,根据需要我们可以修改默认计算脚本。要创建新的计算脚本,在y2013数据库的右键菜单中选【创建】>【计算脚本】。
执行计算脚本的途径有多种,如通过MaxL Shell,Smart View,EAS Console等。要在EAS Console中执行计算脚本,通过右键菜单选【执行计算】,然后选需要执行的脚本。