1. jpivot加入其它应用中
解压jpivot.war 文件,在你的应用当中你需要下面的这些文件:
/wcf/**
/jpivot/**
/WEB-INF/wcf/**
/WEB-INF/jpivot/**
/WEB-INF/lib/**
最后你还需要对比 jpivot.war 里的 web.xml 文件去修改你自己的 web.xml 文件。
2. 例子说明
一个Schema的xml文件,定义立方体;(feeSchema.xml)
一个jsp文件(fee.jsp),使用jpivot的标签(jp:mondrianQuery),写入多维查询表达式。
2.1. 数据库连接
直接用jdbc
<jp:mondrianQuery dataSource="" id="query01" jdbcDriver="oracle.jdbc.driver.OracleDriver" jdbcUrl="jdbc:oracle:thin:ngykt/ngyktadmin@172.16.46.241:1521:orcl10" catalogUri="/WEB-INF/queries/feeSchema.xml">
在应用服务器中定义数据源
<jp:mondrianQuery dataSource="feeDS" id="query01" catalogUri="/WEB-INF/queries/feeSchema.xml">
例子在tomcat中定义了数据源feeDS
2.2. 各种维度类型
一般维度
例子中定义了维度:[term].[所有终端]
按终端id统计缴费情况。
多level维度
例子中定义了维度:[agentTerm].[所有终端]
按代理商,终端两级统计缴费情况
有父子关系维度
例子中定义了维度:[area].[所有地区]
按组织机构级别统计缴费情况
在定义父子级别时,要指定parentColumn和nullParentValue
且要定义Closure,如果不定义,指标钻取的数据有问题。
Closure表针对维度表计算distance,Closure表的生产参见例子中的存储过程sp_zycreateorgclosure
例如:
<Level name="地区" uniqueMembers="true" nameColumn="ORGENTITYNAME" column="ORGENTITYID" parentColumn="ORGENTITYPARENT" nullParentValue="null">
<Closure parentColumn="ORGENTITYPARENT" childColumn="ORGENTITYID">
<Table name="ZY_ORG_CLOSURE"/>
</Closure>
</Level>
3. Mondrian Schema详解
3.1. Schema
Schema 定义了一个多维数据库。包含了一个逻辑模型,而这个逻辑模型的目的是为了书写 MDX 语言的查询语句。这个逻辑模型实际上提供了这几个概念: Cubes (立方体)、维度( Dimensions )、层次( Hierarchies )、级别( Levels )、和成员( Members )。而一个 schema 文件就是编辑这个 schema 的一个 xml 文件。在这个文件中形成逻辑模型和数据库物理模型的对应。
3.2. Cube
一个 Cube 是一系列维度 (Dimension) 和度量 (Measure) 的集合区域。在 Cube 中, Dimension 和 Measure 的共同地方就是共用一个事实表。 Cube 中的有以下几个属性:
属性名 含义
name Cube 的名字
caption 标题 , 在表示层显示的
cache 是否对 Cube 对应的实表用 mondrian 进行存储 , 默认为 true
enabled 是布尔型的 , 如果是被激活 ,Cubes 就执行 , 否则就不予理睬,默认为 true
Cube 里面有一个全局的标签定义了所用的事实表的表名
3.3. Dimension
他是一个层次( Hierarchies )的集合 , 维度一般有其相对应的维度表 . 他的组成是由层次( Hierarchies )而层次( Hierarchies )又是有级别( Level )组成 . 其属性如下:
属性名 含义
name Dimension 的名称
type 类型,有两个可选的类型: StandarDimension 和 TimeDimension ,默认为 StandardDimension
caption 标题 , 在表示层显示的
UsagePrefix 加前缀 , 消除歧义
foreignKey 外键,对应事实表中的一个列,它通过 <Hierarchy> 元素中的主键属性连接起来。
3.4. Hierarchy
你一定要指定其中的各种关系 , 如果没有指定 , 就默认 Hierarchy 里面装的是来自立方体中的真实表 . 属性如下:
属性名 含义
name Hierarchy 的名称,该值可以为空,为空时表示 Hirearchy 的名字和 Dimension 的名字相同。当一个 Dimension 有多个 Hierarchy 时,注意 name 值要唯一。
hasAll 布尔型的 , 决定是否包含全部的成员 member
allMemberName 所有成员的名字 , 也就是总的标题 , 例如: allMemberName= “全部产品”
allLevelName 所有级别的名字,它会覆盖其下所有的 Member 的 name 和所有的 Level 的 name 属性的值。
allMemberCaption 例如 : allMemberCaption= “全部产品”这个是在表示层显示的内容
PrimaryKey 通过主键来确定成员,该主键指的是成员表中的主键,该主键同时要与 Dimension 里设置的 foreignKey 属性对应的字段形成外键对应关系
primaryKeyTable 如果成员表不只一个,而是多个表通过 join 关系形成的,那么就要通过这个属性来指明 join 的这些表中,哪一个与 Dimension 里设置的 foreignKey 属性形成外键关系。通过该属性来指明主表
caption 标题 , 在表示层显示的
defaultMember
memberReaderClass 设定一个成员读取器,默认情况下 Hierarchy 都是从关系型数据库里读取的,如果你的数据不在 RDBMS 里面的话,你可以通过自定义一个 member reader 来表现一个 Hierarchy 。
3.5. Level
级别 , 他是组成 Hierarchy 的部分。属性很多,并且是 schema 编写的关键,使用它可以构成一个结构树, Level 的先后顺序决定了 Level 在这棵树上的的位置,最顶层的 Level 位于树的第一级,依次类推。 Level 的属性如下:
属性名 含义
name 名称
table 该 Level 要使用的表名
column 用上面指定的表中某一列作为该 Level 的关键字
nameColumn 用来显示的时候使用,如果不定义,那么就采用上面的 column 的值来进行显示。
oridinalColumn 定义该 Level 上的成员的显示顺序,如果不指定,那么采用 column 的值。
parentColumn 在一个有父 - 子关系的 Hierarchy 当中,当前 Level 引用的是其父成员的列名。好比是一张部门表,在一张表里表现部门的上下级关系,一个是主键,肯定还有一个字段为连接到该主键的外键的列名,这里的 parentColumn 指的就是这个列名。
nullParentValue 如果当前的 Level 是有上下级关系(设置了 parentColumn 属性),如果该 Level 又处于顶级,我们需要将顶级的数据取出来,这里指的是位于顶级的父成员的值,有些数据库不支持 null, 那么也可以使用 ’0’ 或 ’-1’ 等,这就表示顶级的成员的父 ID 为 ’0’ 或为 ’-1’ 。
type 数据类型,默认值为 string 。当然还可以是 Numeric 、 Integer 、 Boolean 、 Date 等。
uniqueMembers 该属性用于优化产生的 SQL ,如果你知道这个级别和其父级别交叉后的值或者是维度表中给定的级别所有的值是唯一的,那么就可以设置该值为 true ,否则为 false 。
levelType 该 Level 的类型,默认为 regular (正常的),如果你在其 Dimension 属性 type 里选择了 TimeDimension 那么这里就可以选择 TimeYears 、 TimeQuarters 、 TimeMonth 、 TimeWeeds 、 TimeDays 。
hideMemberIf 在什么时候不隐藏该成员,可选的值有三个: Never 、 IfBlankName 、 IfParentName
approxRowCount 该属性可以用来提高性能,可以通过指定一个数值以减少判断级别、层次、维度基数的时间,该属性在通过使用 XMLA 连接 Mondrian 很有用处。
caption 标题 , 在表示层显示的
captionColumn 用来显示标题的列
formatter 该属性定义了 Member.getCaption() 方法返回的动作值,这里需要是一个实现了 mondrian.olap.MemberFormatter 接口的类,用来对 Caption 地值进行格式化。
3.6. Join
对于一个 Hierarchy 来说,有两种方式为其指定:一种是直接通过一个 Table 标签指定;一种是通过 Join 将若干张表连接起来指定。一旦采用 Join 的话,那么就要在 Hierarchy 里的 primaryKeyTable 属性指定主表。
3.7. Measure
Measure 就是我们要计算的数值,操作的核心。它的属性如下:
属性名 含义
name 名称
aggregator 要采用的计算函数
column 要计算的列名
formatString 计算结果的显示格式。
visible 是否可见
datatype 数据类型,默认为 Numeric
formatter 采用类来对该 Measure 的值进行格式,具体参考 Level 的 formatter 属性。
caption 标题,用来显示时使用。
4. JPivot标签库使用详解
4.1. Introduce
JPivot 是一套基于 Mondrian 的 OLAP 前端展现工具,它提供了一套标签库来解决的 OLAP 的展现层问题。
在一个 JSP 页面当中,如果要使用 JPivot 标签库,除了要配置相关的配置文件外,我们需要在 JSP 头的位置声明对 JPivot 标签库的引用,引用方法如下:
<%@ taglib uri = "http://www.tonbeller.com/jpivot" prefix = "jp" %>
JPivot 标签库包含以下几个标签:
chart
chooseQuery
clickable
destroyQuery
mondrianQuery
navitator
print
scalarQuery
setParam
table
testQuery
xmlaQuery
接下来我们将详细介绍这些标签的具体用法及相关参数的含义。
4.2. chart
创建一个图表组件,这个图表组件的标签不能直接产生可见输出,它必须通过 WCF 的渲染标签才行。 chart 标签的主要属性如下:
属性名 必须 数据类型 是否能动态计算指定 描述
id 是 String 是 标签的 ID
visible 否 boolean 是 用来设置该组件是否可见,当该属性为 false 时 WCF 标签半角不显示该组件。
role 否 String 是 Role 的名称,如: role=”tomcat” 就允许当前用户角色为 tomcat 的访问该控件, role=”!tomcat” 则就允许除角色为 tomcat 以外的所有的用户访问。
query 是 OlapModel 是 一个 mondrianQuery 标签的 ID 值
baseDisplayURL 否 String 是 显示图表的链接,链接的后面还要添加参数“ ?=filename=[ 临时图表文件的名称 ] ”
controllerURL 否 String 是 链接到 JPivot Controller 的 URL ,该属性在一些复杂环境下比如 Portal 之类就很有用。
4.3. chooseQuery
从前面创建的若干个查询当中选择一个合适的查询(通过查询名称进行选择),例如:
<jp:mondrianQuery id="query01" queryName="name1">
SELECT ...
</jp:mondrianQuery>
<jp:mondrianQuery id="query01" queryName="name2">
SELECT ...
</jp:mondrianQuery>
...
<jp:chooseQuery id="query01" queryName="name1"/>
它的属性比较简单,只有 id 和 queryName 两个,而且比较容易理解。
4.4. clickable
该标签的作用是给一个 dimension 或一个 level 里的所有的 members 加上超链,使得它们变的可以进行点击操作。生成的 URL 中包含这个 member 的唯一名称,这个标签必须要在一个 table 或一个 query 的标签里嵌套使用。
这个动作还依赖于该标签的 sessionParam 属性,如果该属性存在,那么参数值将在页面显示之前写到 com.tonbeller.jpivot.param.SessionParamPool 当中,如果不存在该属性,参数将会被编码到超链接当中。
例如:
<jp:mondrianQuery ...>
select .. from Sales
<jp:clickable urlPattern="/otherpage.jsp?param={0}" uniqueName="[Customers]"/>
<jp:clickable page="/yetotherpage.jsp" uniqueName="[Products].[Category]" sessionParam="Category"/>
</jp:mondrianQuery>
该标签的主要属性如下:
属性名 必须 数据类型 是否能动态计算指定 描述
urlPattern 否 String 是 该属性已过时,使用 page 属性替代它。
page 否 String 是 目标页面的名称,该属性的值必须要以“ / ”开始,如果不设置,那么会采用当前页面的名称。
uniqueName 否 String 是 一个 dimension 或 hierarchy 或 level 的唯一名称,用来标识哪个 member 将可以点击。
menuLabel 否 String 是 如果多次定义 clickable ,那么它将通过一个右键来进行显示,这里的值就是右键菜单的名称。
sessionParam 否 String 是 参数名称,它将会被回写到 com.tonbeller.jpivot.param.SessionParamPool 当中。
propertyName 否 String 是 该属性如果存在,该 member 属性的值将会被带到 com.tonbeller.jpivot.param.Parameter 的 sqlValue 的属性当中。
propertyPrefix 否 String 是 如果存在该属性,多个 SessionParam 将会被创建,每一个 member 的名字的开始部分将采用该属性的值。
providerClass 否 String 是 如果存在该属性,这个类的实例将会从当前的 member 中获取 SessionParam 对象的实例,这里的类必须实现 com.tonbeller.jpivot.table.navi.ClickableMember.ParameterProvider 接口。
4.5. destroyQuery
该标签的主要作用是销毁所有的查询,它的用法如下:
<jp:destroyQuery id="query01"/>
它只有一个 ID 属性。
4.6. mondrianQuery
该标签的主要作用是让 mondrian 执行指定的查询,该标签需要指定一个 JDBC 的 datasource 或单独指定 JDBC 连接的各个属性从而可以让 mondrian 连接到指定的数据库。
它的用法如下:
<jp:mondrianQuery id="query01"
jdbcDriver="com.mysql.jdbc.Driver"
jdbcUrl="jdbc:mysql://localhost/foodmart"
catalogUri="/WEB-INF/test/FoodMart.xml">
select
{[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} on columns,
{[Product].[All Products]} ON rows
from Sales
where ([Time].[1997])
</jp:mondrianQuery>
它的主要属性如下:
属性名 必须 数据类型 是否能动态计算指定 描述
id 是 String 是 标签的 ID
jdbcDriver 否 String 是 要连接到目标数据库的驱动类名
jdbcUrl 否 String 是 目标数据库的 URL
jdbcUser 否 String 是 登录数据库的用户名
jdbcPassword 否 String 是 登录数据库的密码
dataSource 否 String 是 可以连接到数据库的 JNDI 名称,如 jdbc/SampleDB ,当使用它时另外四个单独连接数据库的属性不可以再用。
catalogUri 是 String 是 Mondrian Schema 文件所在的路径,指定路径时需要从 web 应用的根开始,如 /WEB-INF/FoodMart.xml 。
role 否 String 是 指定角色,该角色的值来自 Mondrian Schema 里定义的角色。
dynResolver 否 String 是 指定一个用来解析 Mondrian Schema 里定义的动态变量的解析类。
connectionPooling 否 String 是 当该值为 false 时,将从连接池里阻止 Mondrian
dynLocale 否 String 是 设置动态解析 Mondrian Schema 里的 Local
dataSourceChangeListener 否 String 是 指定一个类用来检测 datasource 的变化。
queryName 否 String 是 这个属性允许保留多个查询,对于每一个查询,最后一个查询将会被存储下来,可以使用 chooseQuery 标签在查询间进行切换。
stackMode 否 boolean 是 如果设置为 false ,那么所有的查询将同时被处理;如果设置为 true ,那么将保持其原有的顺序,例如:
查询名称为 qn1 的创建后,标签就马上将其显示出来 ; 接下来创建 qn2 ,现在 stack 里有 qn1 和 qn2 , qn2 也将被显示出来。
4.7. navigator
创建一个导航组件,这个组件不会直接输出,它必须通过 WCF 的标签来 render 输出。
示例用法:
<jp:navigator id="navi01" query="#{query01}" visible="false"/>
<wcf:render ref="navi01" xslUri="/WEB-INF/jpivot/navi/navigator.xsl" xslCache="true"/>
该标签的主要属性如下:
属性名 必须 数据类型 是否能动态计算指定 描述
id 是 String 是 标签的 ID
query 是 OlapModel 是 指定一个 mondrianQuery 标签的名称
visible 否 boolean 是 设置该组件是否可见,如果设置为 false 那么 WCF 的 render 标签将不会 render 该组件。
role 否 String 是 角色的名称,可以加前缀“!”,表示“除 … 角色之外”都可以访问该组件,否则就是只有该角色才能访问该组件。
4.8. print
创建一个打印控件,该控件不能直接输出,你必须创建 WCF form 来调用打印的 servlet 来生成 XLS/PDF 文件。
该标签只有一个 ID 属性。
4.9. scalarQuery
创建一个包含由单个单元格的组成的 OLAP 结果的会话属性,它的值由标签的属性提供。
示例用法:
<jp:scalarQuery
id="query01"
value="#{some.bean.property}">
formattedValue="#{some.bean.otherProperty}"
caption="Some Caption" />
它的主要属性如下:
属性名 必须 数据类型 是否能动态计算指定 描述
id 是 String 是 标签的 ID
value 是 String 是 是一个 EL 的表达式,通过 EL 表达式来计算值,这里是一个数字。
formattedValue 否 String 是 用一个 EL 表达式来计算格式化后的值,是一个字符串
caption 否 String 是 用一个 EL 表达式来生成 caption 的值,这里是一个字符串
queryName 否 String 是 请参考 mondrianQuery 标签
stackMode 否 boolean 是 请参考 mondrianQuery 标签
4.10. selectProperties
创建一个选择属性的组件,该组件不会直接输出,必须要与 WCF 的 render 标签结合。
示例用法:
<jp:selectproperties id="selectprop01" table="#{table01}" visible="false"/>
<wcf:render ref="selectprop01" xslUri="/WEB-INF/jpivot/navi/navigator.xsl" xslCache="true"/>
它的主要属性如下:
属性名 必须 数据类型 是否能动态计算指定 描述
id 是 String 是 标签的 ID
table 是 TableComponent 是 该属性用来指定一个表格组件。
visible 否 boolean 是 设置该组件是否可见,如果设置为 false 那么 WCF 组件将不会显示该组件。
role 否 String 是 指定角色,同样可以使用“!”
4.11. setParam
通过 get 或 post 或 session 里的值为 MDX 查询设置查询参数。示例用法:
<jp:mondrianQuery id="query01"...>
SELECT ... Parameter("Param01", ...
WHERE ...
</jp:mondrianQuery/>
<jp:setParam query="query01" httpParam="param" mdxParam="Param01"/>
or
<jp:setParam query="query01" sessionParam="CUSTOMER" mdxParam="Param01"/>
它的主要属性如下:
属性名 必须 数据类型 是否能动态计算指定 描述
query 是 OlapModel 是 指定一个 mondrianQuery 标签的名称
httpParam 否 String 是 http 参数的名称,如果存在该属性,那么它的值将会被告解析并设置到 mdx 查询的 parameter 当中
sessionParam 否 String 是 Session 的参数名称
mdxParam 是 String 是 MDX 的 parameter 的名称
4.12. table
创建一个 pivot 的表格组件,该组件要借助于 WCF 的 render 标签输出。
示例用法:
<jp:table id="table01" query="#{query01}" visible="true"/>
该标签的主要属性如下:
属性名 必须 数据类型 是否能动态计算指定 描述
id 是 String 是 标签的 ID
visible 否 boolean 是 设置组件是否可见,如果为 false 那么 WCF 的标签将不会将其 render 。
role 否 String 是 可访问该组件的角度,支持“!”用法
query 是 OlapModel 是 指定一个 mondrianQuery 标签的名称
5. 多维查询表达式
5.1. 什么是 MDX
MDX 的全称是 Mutil Dimensional Expressions ,是由 Microsoft , Hyperion 等公司研究多维查询表达式,是所有 OLAP 高级分析所采用的核心查询语言。
MDX 可以用来进行以下操作:
1. calculated members (计算成员)
2. Calculated Cells (计算单元)
3. Security Settion (安全设置)
4. Custom member formula ( 自定义函数 )
5. Custom level rollup ()
6. Actions (动作)
7. Named “ sets ” ( 命名集合 )
8. Server side formatting (服务器数据格式化)
5.2. MDX 的基本结构
MDX 的基本结构有三种: Members 、 Tuple 、 Set 。
5.2.1. Members
指的是维度树上的一个节点,这里有一点需要指出,量度也是一个特殊的维度,所以对于普通维度上的 Member 可以有几下几种表示方法: [Customer] 或 [Time].[1996] 等,对于特殊的维度——量度而言,也可以表示一个 Member ,如: [Measures].[ unit sales] 等。
Member 的表示方法就是用中括号的形式,“ [……] ”。
5.2.2. Tuple
Tuple :是由若干个 Members 组成,每一个维度上最多只能有一个 Member ,对于一个 Tuple 而言至少有一个维度,多则不限,同时对于没有列出来的那就表示为默认的 Member 。 Tuple 的表示方法是小括号“ () ”,因为其又有 Member 构成,所以通常的格式为“ ([…],[…][…],…) ”;示例:
a) ([Regin ].[USA])
b) ([product].[ computers],[time].[2008]) 。
5.2.3. Sets
同一维度上若干个 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 也必须是一个国家名,依次类推。
5.3. MDX 查询语句
一个标准的 MDX 查询语句就是由我们前面介绍的 MDX 的三个基本对象构成,也就是 Member 、 Tuple 、 Set 。
一个标准的 MDX 查询的语法如下:
SELECT Set ON COLUMNS,
Set ON ROWS
FROM Cube
WHERE Tuple
示例:
SELECT
{[time].[ 1997],[time].[1998]}
ON COLUMNS,
{([product].[drink],[customer].[gender].[F]),( [product].[food],[customer].[gender].[M])}
ON ROWS
FROM
[Sales]
WHERE
([Measures].[ StoreSales ])
这个 MDX 查询就表示:查询时间为 1997 和 1998 两年的 drink 类产品,女消费者和 food 类产品男消费者的 Store Sales 。
5.4. MDX 表达式
5.4.1. children
它的作用是列出指定分类下的所有项,如
1. [product type].[food].children ,这就表示列出产品类型为 food 的所有产品。
2. [region ].[country].children ,这就表示列出所有的国家名称。
该函数不能用在 Tuple 中
5.4.2. CurrentMember
当前某个 Member ,举例:
某个产品销售额贡献度计算,对于某一个产品或一种类型的产品而言它的销售额贡献度指的是它的销售额与所有产品销售额的比值,此时,如果我们要用 MDX 来计算这个贡献度的值是可以采用 CurrentMember 来实现,如:
此时我们的 MDX 表达可以是:
([product].currentMember ,[ Measures].[stores sales]) / ([product].[ all products],[Measures].[stores sales])
同时因为默认情况下指的就是 currentMember ,所以上面的 currentMember 可以去掉:
([Measures].[ stores sales]) / ([product].[ all products],[Measures].[stores sales])
所有 MDX 表达式的写法是由若干个 Tuple 组成 ,比如上面的这个表达式就是由两个 Tuple 的相除构成。
5.4.3. prevMember 和 nextMember
这两个元素分别指的是当前 Member 的上一个 Member 和当前 Member 的下一个 Member 。
利用这两个元素我们可以来实现实际当中常见的同期比(前期比),所谓的同期比指的 是:
(当前 member- 当前 member 的前一个 member ) / 当前 member 的前一个 member
对应到 MDX 表达式我们可以用 prevMember 和 nextMember 来实现,如:
(([time].currentMember ,[ Measures].[store sales])-([time].prevMember ,[Measures].[storessales ]))
/
([time].prevMember ,[ Measures].[store sales])
当然因为 currentMember 可以省略,所以上面的写法也可以是:
(([ Measures ].[store sales])-([time].prevMember ,[Measures].[storessales ]))
/
([time].prevMember ,[ Measures].[store sales])
5.4.4. Parents 、 FirstChild 、 Descendants
下面的这张图就显示一个树
这张图中 all 这个节点是 97 和 98 的 parents , 97 和 98 也是 all 的 children ,同时 97 是 all 的 firstChild
如果我们要取到 97 下的所有的月份,那么我们就需要用 Descendants 来实现,它的语法是:
Descendants( [time].[97],month) ,这里的 month 是一个 level 的名称。所有它的格式为: Descendants([ 一个 Member], 一个 level 的名称 )
比如在食品销售当中,我们要知道哪一类的食品更受消费者欢迎,这样我们需要只知道各类食品的销量,比如食物( food )、饮料 (drink) 等的具体销量 (unit sales) ,然后再计算出所有食品总的销量( total sales ) , 如果采用 MDX 我们可以很容易的实现,采用 MDX 后的计算哪种食品更受欢迎的表达式如下:
([food].currentMember ,[ Measures].[unit sales])
/
([food].currentMember.parent ,[ Measures].[total sales])
因为 currentMember 可以省略,所以上面的写法又可以是:
( [ Measures].[unit sales])
/
([food].currentMember.parent ,[ Measures].[total sales])
5.5. 参见MDX的基本语法及概念.pdf
6. 常见问题
6.1. MDX编辑器中文乱码
web.xml中添加过滤器
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>com.tonbeller.wcf.charset.CharsetFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意,该filter-mapping放在所有filter-mapping的最前面
jsp页面编码用UTF-8(testpage.jsp)
6.2. pdf中文显示“#”
1).在WEB-INF\jpivot\print目录下建立userconfig.xml文件。内容如下:(仅配置黑体,fontBaseDir属性我也没有配置,源码中有)
<configuration>
<fonts>
<font metrics-file ="simhei.xml" kerning ="yes" embed-file ="simhei.ttf">
<font-triplet name ="SimHei" style ="normal" weight ="normal"/>
<font-triplet name ="SimHei" style ="normal" weight ="bold"/>
<font-triplet name ="SimHei" style ="italic" weight ="normal"/>
<font-triplet name ="SimHei" style ="italic" weight ="bold"/>
</font>
</fonts>
</configuration>
2). 下载Apache的FOP包,应用所需JAR包,生成simhei.xml。Java命令行为:
java -cp D:\op\fop.jar;D:\op\avalon-framework-4
.2.0.jar;D:\op\commons-logging-1.0.4.jar;D:\op\commons-io-1.1.jar;D:\op\xmlgraph
ics-commons-1.4.jar org.apache.fop.fonts.apps.TTFReader C:\WINDOWS\Fonts\simhei.
ttf simhei.xml
3). 将simhei.xml,以及simhei.ttf文件放到WEB-INF\jpivot\print目录下。
4 ). 修改WEB-INF\jpivot\table目录下的fo_mdxtable.xsl文件,把所有的font-family对应成SimHei,(以SimHei开头)。
6.3. pdf格式修改(原格式行太宽)
修改jpivot\WebRoot\WEB-INF\jpivot\table\fo_mdxtable.xsl
中font-size,line-height,padding
6.4. 钻取数据的格式化
在利用jpivot钻取的时候,发现出来的数字数据都精确到了小数点后两位,我可不想所有数字都这么精确,连带出来的id值也被这样格式化了,悲惨!
我的解决方法:取消格式定义
找到wcf.jar,修改com.tonbeller.wfc.format.config.xml
删除double和nandouble的定义
6.5. mondrian 的志的配置
将log4j.xml放置到web-inf/classes下
文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!-- ================================================== =================== -->
<!-- -->
<!-- Log4j Configuration -->
<!-- -->
<!-- Default log configuration file for the Workbench. -->
<!-- Copied to the user home directory, where the user can change -->
<!-- settings for their own purposes. -->
<!-- -->
<!-- Sends log messages to the console and the workbench.log file -->
<!-- in the user's home directory. -->
<!-- -->
<!-- ================================================== =================== -->
<!-- $Id: //open/mondrian/log4j.xml#2 $ -->
<!--
| For more configuration infromation and examples see the Jakarta Log4j
| owebsite: http://jakarta.apache.org/log4j
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<!-- ================================= -->
<!-- Preserve messages in a local file -->
<!-- ================================= -->
<!-- A size based file rolling appender, capturing everything -->
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="e:/workbench.log"/>
<param name="Append" value="false"/>
<param name="MaxFileSize" value="500KB"/>
<param name="MaxBackupIndex" value="1"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
</layout>
</appender>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<!-- 设置监视器输出方式 -->
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%-4r [%t] %-5p %c %x - %m%n" />
</layout>
</appender>
<!-- ============================== -->
<!-- Append messages to the console -->
<!-- ============================== -->
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<param name="Threshold" value="WARN"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
</layout>
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<!-- Limit the org.apache category to INFO as its DEBUG is verbose -->
<category name="org.apache">
<priority value="INFO"/>
</category>
<category name="com.tonbeller">
<priority value="WARN"/>
</category>
<category name="mondrian.rolap">
<priority value="WARN"/>
</category>
<category name="mondrian.gui">
<priority value="WARN"/>
</category>
<category name="mondrian.sql">
<priority value="DEBUG"/>
</category>
<category name="mondrian.mdx">
<priority value="DEBUG"/>
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="INFO"/>
<appender-ref ref="FILE"/>
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
6.6. schema workbench
schema的编辑器,界面化编辑schema。
但不知道为什么,在我的本机上,在打开,新建schema文件,都非常慢。
可以到http://sourceforge.net/projects/mondrian/files/下载,最新版本psw-ce-3.2.1.13885
7. 参考资料
http://mondrian.pentaho.com/documentation/ mondrian的官方网站
http://jacky6024.javaeye.com/ 比较有用的中文资料