Oracle 从10g开始支持model高级语句,使用model语句,可以在表上定义一个数据立方体,这个立方体由它的维度和度量定义,并通过规则对每个单元的值进行计算,这相当于是把关系表转换成了多维数组,这个多维不止可以是三维,可以是包含一维、二维的任意维度。这样也就提供了一种在oltp数据库里进行olap的方法。
1 model语句的基本语法
model语句的语法在Oracle数据库里是比较复杂的,其基本语法可以从一个简单的例子看到,示例代码中用到的基表已经实现创建,只有三条数据
SQL>select*from t; DIM1 DIM2 VALUE ---------- ---------- ----------001012103
一个简单的model语句如下面所示:
select*from t model dimension by(dim1, dim2)--定义维度measures (value,0 result)---定义度量(-----定义规则 result[0,0]=-1)
model后面由三部分组成,dimensiond定义数据立方体的维度,定义维度的列必须是基表里的列,measures定义数据立方体的度量,度量可以来自基表,也可以自己定义,最后括弧里面定义的是用于计算度量的规则集。这些规则集默认按照顺序应用的刚才定义的数据立方体上。规则集必须存在,但可以为空,下面看一下数据立方体是怎么定义的。
2 定义立方体
model语句的执行类似于过程语言,先定义一个数据立方体,然后按照顺序在这个立方体上应用规则里定义的规则。通过一个规则集为空的例子可以简单直接地看到model语句是如何定义数据立方体的。
SQL> with t(id, value)as(select rownum, rownum from dual connect by level <=3)select*from t model dimension by(id) measures (value,100 r1,100 r2)(); ID VALUE R1 R2 ---------- ---------- ---------- ----------111001002210010033100100
上面的示例中,规则集为空,定义立方体后没有应用任何规则,基表由with语句定义,是一个3行3列的表,由model定义的立方体中,使用基表中的id作为维度,value作为度量,另外又定义了两个度量r1,r2,基表中有的度量值使用基表中的值作为数据立方体相应单元的值,基表中没有的值则使用度量中指定的值(度量定义前面的数字)作为默认值。
3 规则的定义和使用
model语句的复杂性在于它支持复杂的规则定义,为了简单直观,这里还是使用示例来说明
select*from t model dimension by(dim1, dim2)measures (value, cast(nullas number) result)( result[0,0]=-1,--位置引用 result[dim1=1, dim2=0]=-3,---符号引用 result[-1, for dim2 in(selectcount(*)from dual)]=-4,--位置引用 result[-2, dim2=1]=-10,--混合引用 result[-3, dim2=-1]=-100,--混合引用 result[-4,-1]=-1000----位置应用)orderby dim1, dim2;
表t还是上面定义的表,这里定义了6条规则,要想理解这6条规则,首先要理解几个概念和定义。首先,对每一条规则来说,等号的左边是要操作的单元,等号的右边是对单元的赋值或者操作,等号左边需要引用要操作的单元,这里有三种引用方法,符号维度引用、位置维度引用和混合维度引用,所谓的符号维度引用,必须是一个包含维度名称的表达式,比如上面示例中的result[dim1=1, dim2=0],除了符号位置应用之外的则是位置维度引用,简单的位置维度引用比如上面例子中的result[0,0],值得注意的是,像result[-1, for dim2 in (select count(*) from dual)]这样复杂的引用也是位置维度引用,混合维度引用是在多个维度引用时,一部分维度是符号维度引用,一部分维度是位置维度引用,如上面的示例中的result[-2, dim2=1]。
为什么要区分符号维度引用和位置维度应用,这两种引用的区别在哪里?简单来说,符号维度引用用来引用已经存在的数据,位置维度引用可以用来引用必须要加入的数据,这些数据本来不存在。至于混合维度引用,上面的规则依然使用,混合维度里符号维度必须为已存在的数据,位置维度则可以为不存在的需要加入的数据。
这样的区分有实际意义吗?其实是有的,关键在于Oracle对立方体里的单元的处理方式。Oracle对立方体内的单元的处理方式有三种,有三个关键字update/upsert all/upsert来定义,update只更新立方体内已有的数据,upsert在更新存在的单元的同时,也创建位置维度引用的不存在的单元,upsert all和upsert不同的是,它还创建混合应用中符号维度引用已经存在的单元。默认的处理方式是upsert。说起来比较枯燥,还是使用示例来说明比较直观。先看默认的方式即upsert
select*from t model dimension by(dim1, dim2)measures (value, cast(nullas number) result)( result[0,0]=-1,--位置引用 result[dim1=1, dim2=0]=-3,---符号引用 result[-1, for dim2 in(selectcount(*)from dual)]=-4,--位置引用 result[-2, dim2=1]=-10,--混合引用 result[-3, dim2=-1]=-100,--混合引用 result[-4,-1]=-1000----位置应用)orderby dim1, dim2;DIM1 DIM2 VALUE RESULT ---------- ---------- ---------- -----------4-1-1000---位置引用-11-4----位置引用。dim2 维度是select语句定义的001-1---数值数据集012103-3
上面的示例中,注释已经说的比较清除了,后面三行数据引用的是原始的数据立方体里的数据,另外两行数据的单元都是位置维度引用的。混合维度引用和符号维度引用的单元在这里没有出现。下面看一下update的情况
select*from t model dimension by(dim1, dim2) measures (value, cast(nullas number) result) rules update( result[0,0]=-1,--位置引用 result[dim1=1, dim2=0]=-3,---符号引用 result[-1, for dim2 in(selectcount(*)from dual)]=-4,--位置引用 result[-2, dim2=1]=-10,--混合引用 result[-3, dim2=-1]=-100,--混合引用 result[-4,-1]=-1000----位置应用)orderby dim1, dim2; DIM1 DIM2 VALUE RESULT ---------- ---------- ---------- ----------001-1012103-3
只有原始数据立方体内存在的数据。最后是upsert all
select*from t model dimension by(dim1, dim2) measures (value, cast(nullas number) result) rules upsert all ( result[0,0]=-1,--位置引用 result[dim1=1, dim2=0]=-3,---符号引用 result[-1, for dim2 in(selectcount(*)from dual)]=-4,--位置引用 result[-2, dim2=1]=-10,--混合引用 result[-3, dim2=-1]=-100,--混合引用 result[-4,-1]=-1000----位置应用)orderby dim1, dim2; DIM1 DIM2 VALUE RESULT ---------- ---------- ---------- -----------4-1-1000--位置引用-21-10--混合引用,符号引用的维度在初始数据集中存在-11-4--位置引用001-1--初始数据集012103-36 rows selected.
上面出现的数据包含数据立方体原始数据,位置维度引用数据,以及一行混合维度引用数据,这行混合维度应用数据在这里出现的原因是它的符号维度应用dim2=1在原始的数据立方体内存在,尽管它的位置维度引用-2在原始数据立方体里不存在,而另一个混合维度引用单元result[-3, dim2= -1]在结果集里不存在是因为它的符号维度引用dim2= -1在原始数据立方体里不存在。从上面的例子里可以看出,使用符号维度引用原始立方体里不存在的维度值是没有意义的,做的计算也只是无用功。