通过语义层小节的学习,相信你已经对元数据文件的制作有了初步了解,其实元数据中除了可以做一些常规的设置外,还可以做一些高级设置,比如外键、假表层函数、子表等。在上一小节中讲述了高级设置的使用,本节将主要针对这些高级元数据设计做进一步介绍。
在元数据中可以自定义外键。与数据库中的概念相似,DQL中,表的外键字段指向另一张表的主键,从而产生关联。

Foreign key name:外键的名称可以直接编辑,设定时不允许与本表的其它外键名称相同,否则引用外键时会产生错误;如果当前外键是由单外键字段组成的,那么外键名称通常可以不使用,而是用外键字段来代替;如果当前外键是由多个外键字段组合成的,那么在引用外键指向表的字段时,只能使用Foreign key name,如上图中fk1、fk2和fk3均为外键名称,选中外键的外键名称是fk2。
Referenced table name:外键所指向的表名,当指向表的主键唯一且非外键时,那么这个表称为维表,简称维,如上图所示的维是:Product。
Referenced field:外键指向表的主键,如上图所示的引用字段是:ProductID,即ProductID是Product表的主键。
Foreign key filed:当前表的字段,和引用字段一一对应,如上图中所示Inventory表的外键字段是:ProductID
在DQL中,外键字段和维字段的地位是完全一样的,可以把外键字段看成维字段。
任何表的主键都可以视为维字段。如果某个表的主键是外键,那么这个主键的维即为外键指向的维;如果主键并非外键,那么这个主键的维就是它本身。对于非主键的字段,只有当它是外键时才是维字段,字段的维即为外键指向的维。
举例:

根据上图所示,“ReturnedPmt”表中的CustomerID字段指向“Customer”表的CustID字段,“ReturnedPmt”表与“Customer”表之间的数据关系为多对一的关系,其中的相关概念描述如下:
外键字段:“ReturnedPmt”表的CustomerID字段
维表:“Customer”表
引用字段:“Customer”表的主键CustID字段
写DQL的时候,可以像引用属性一样引用外键表的字段,比如:SELECT CustomerID.CustName,Date,Amount FROM ReturnedPmt,这里CustomerID.CustName引用的是CustomerID指向的“Customer”表的CustName字段。
知识点:
1) 对于单一字段形成的外键,在使用DQL时,可以用外键字段.外键表的字段名的方式来直接使用。
2) 对于多字段组成的外键,在使用DQL时,可以用外键名称.外键表的字段名的方式来直接使用。
3) 使用外键名称.外键表的字段名方式引用,既可用于多字段组成的外键,也可用于单一字段形成的外键情况。
通过使用层函数,可灵活定义多维度的层次结构,如时间维度的 “年、年月、日”,地理维度的 “国家、省、市” 等,使用户能够在不同粒度上分析数据。这类层次结构在元数据编辑设计器中只需一次定义,即可在多处复用,极大提升了数据分析的灵活性。
在元数据定义中,当表间的外键关系设定之后,系统会根据外键设定中产生的维信息,自动生成维的相关定义。然后可以在元数据的维和层页面里,定义这几个维度间的计算关系。

当表中函数的参数为某个维度,且返回的维度与原维度不同时,该函数称为层函数。通过定义维的各个层次关系,使用户能够在不同的粒度上观察数据。
对于层次结构的定义,通常有几个维度就定义几张表(或假表)。例如,地理维度可拆分为 “地区表、省表、城市表” 三张表,分别对应 “地区、省、市” 三个层级。业务表中的字段需与对应层级的表建立关联,比如:若业务表存储 “市” 级数据,字段需关联 “市表”;若存储 “地区” 级数据,字段需关联 “地区表”。
以demo.glmd中的Province(省表)、Area(地区表)、City(城市表)为例,表结构及数据内容如下:

使用以上三个表定义层次:
City:

Province:

Area:

说明:
1) 在层间计算式中用?表示源字段表,比如以下设置表示“Area”维Area字段的值可以由“Province”维的PRMunicipalityCode字段通过表达式?/100计算而来:

定义好层结构后,就可以在DQL中直接使用定义中的任何结构,比如:

在Customer表CityCode是个数值型字段,在Customer表的外键定义中,我们将“Customer”表的字段CityCode与“City”表的字段City建立外键关系,如下图:

这样,我们就可以在DQL中获得CityCode的省、地区等信息了,如CityCode#Province,得到CityCode的省,CityCode#Area就得到了CityCode的地区:
DQL: SELECT CustID,CustName,Contact,ContactTitle,CityCode,CityCode#Province Province,CityCode#Area Area FROM Customer

DQL: SELECT count(CustID) CustNumber ON Area FROM Customer BY CityCode#Area

DQL: SELECT count(CustID) CustNumber ON Province FROM Customer BY CityCode#Province

知识点:
1)维中的表达式使用dql标准函数语法,层中的表达式使用spl表达式语法。
假表是一种虚拟的单字段无记录表,可以视为普通表来使用,主要用于在无实体表的场景下定义维度层次,如时间维度通常没有实体表,此时就可以通过假表实现。
以demo.glmd中通过Day、Year、YearMonth三张假表定义的日期层次为例:



说明:
1) 系统已为日期维度预定义常用层函数:
|
year |
年 |
|
season |
季 |
|
month |
月 |
|
day |
日 |
|
week |
星期几,1表示星期天 |
|
yseason |
带有年的季 |
|
ymonth |
带有年的月 |
|
weeks |
总第几周 |
|
yweeks |
当前的第几周 |
|
sweeks |
当季的第几周 |
|
mweeks |
当月的第几周 |
2) 层间计算式也可以理解为从细向粗计算。比如“Day”维,只能从日算出年,不能从年算出日。
3) 目标维可分别通过多个源维进行换算。比如“Year”维,可能是从日聚集到年,也可能从年月聚集到年,因此,对于“Year”维,就要定义两个层间计算式,分别从“Day”表的日期和“YearMonth”表的年月计算而来。
接下来可以在DQL中直接使用定义定义好的日期层函数,如下例:

ReturnedPmt表中RDate是个日期类型,在ReturnedPmt表的外键定义中,我们将“ReturnedPmt”表的字段Date与“Day”表的字段Day建立外键关系,如下图:

这样,我们就可以在DQL中获得RDate的年、月等信息了,如Date#Year,得到RDate的年份,RDate#YearMonth就得到了RDate的年月
DQL: SELECT CustomerID,ID,RDate,RDate#YearMonth YearMonth,RDate#Year Year,Amount,SellerID FROM ReturnedPmt

DQL: SELECT sum(Amount) Sum_Amount ON Year FROM ReturnedPmt by RDate#Year

DQL: SELECT sum(Amount) Sum_Amount ON YearMonth FROM ReturnedPmt by RDate#YearMonth
在元数据中,当A表中有多个主键时,对部分主键字段添加外键后,在外键对应的主表中会自动将A表做为子表列出。
部分主键字段构成外键指向的表是主表;单字段主键的层函数的维表是主表;主表的主表是主表;同维表的主表是主表;主表的同维表是主表。
注意:要求主子表的主键按次序对应,主子表还要求按主键有序。子表外键必须关联主表主键字段。
例如:

CustID为Customer表中的主键字段,ReturnedPmt中CustomerID和ID为主键字段,ReturnedPmt的CustomerID外键指向Customer表的CustID。
ReturnedPmt中外键设置如下:

在Customer表中会自动添加子表ReturnedPmt,如下:

通过设定主键和外键,使得表与表相互关联。根据外键关联,可以获得Customer表以及与Customer表同维的VIPCustomer等表的信息。通过Employee表的外键关联,可以获得City表的信息,等等。
表的外键,同维表的外键,广义外键关联表的外键,通称为广义外键,另外,广义外键的层函数也是一种广义外键。
表的字段,同维表的字段,广义外键关联表的字段,广义字段的层函数通称为广义字段。
用广义字段定义的表达式,通称为伪字段,按普通字段处理,但不作为外键。
通过在元数据中设定伪字段,可以命名一些常用的广义字段,可以使得对它们的查询语句更为精简方便。例如:

如果在ReturnedPmt中定义广义字段VIPCustomer_End结束如下:

伪字段可以相当于普通字段使用,如查询的DQL可以写成:SELECT VIPCustomer_End FROM ReturnedPmt,而不必写为SELECT CustomerID.EndTime#YearMonth FROM ReturnedPmt。
注意:伪字段是用宏替换方式实现的,不能再使用层函数。