目录
正文开始前补充说明一下:
如果SAP中SFLIGHT模型的表中没有数据,可以使用SE38运行程序SAPBC_DATA_GENERATOR进行数据填充,如果选择填充大量数据建议后台运行。
一、基本概念
1.与Join的区别
联接(Join)不管是否检索Join表的字段,Join都会执行;而关联(Association)则是按需连接,不需要时刻关联只是说明了一个关联(暴露关联),除非触发关联,否则不会执行实际的链接,这样可以提高性能。(特殊的Association也是可以做到常连接的,那样就和Join没有区别)
注:Join和Association在数据库级别没有任何区别,最终任何关联都会转换为普通关联
2.语法模版
在创建时会有Association的模版如下:
3.一个简单的例子
@AbapCatalog.sqlViewName: 'ZVCDS_ASS_TEST'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Association test'
define view ZCDS_ASS_TEST as select from spfli as a
association [1..*] to sflight as _sflight
on $projection.carrierid = _sflight.carrid
and $projection.connid = _sflight.connid
{
key a.carrid as carrierid,
key a.connid,
a.cityfrom,
a.cityto,
_sflight
}
结果:
1).Association的别名是以下划线开头
2). _sflight就是暴露出来的关联,再上面结果中spfli没有与sflight进行连接,当用户使用关联查看时就会建立连接,如下
右键选择Follow Association可以查看关联数据
3).$projection需要在on的部分使用,任意名字,但是指定的任意名字需要在实际选择里用别名来确定任意名字对应的真实字段
如:例子中的: CarrierId再后面的实际选择中a.Carrid的别名与其一致,这样就确定了是CarrierId是那个字段
4).数据库层面
右键eclipse代码编辑界面选择Show SQL Create Statement可以查看数据库级别的创建代码
二、关于基数
1.含义
基数(Cardinality):是源表和关联表(或CDS视图)之间的关系。
注:基数仅仅是为关联的表/视图定义的。[ .. ]的两边并不是源表和关联表的数量
2.规则
1).非必须定义,未定义会有一个默认的隐式基数[0..1]
2).最小值的默认值0,例如: [1] -> [0..1]
3).最小值不能为*,最大值不能为0
当指定的最大值大于1时的语法检查
4).Association 不能用在where,会报语法错误:“Value-set associations are not allowed here”“此处不允许使用值集关联”
5).元素列表中使用时,会发出语法警告:“Association <…> can influence the cardinality of the resulting set”“关联<…>会影响结果集的基数”
3.基数如何影响访问CDS视图的结果
@AbapCatalog.sqlViewName: 'ZVCDS_ASS_02'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: '基数测试[0..1]'
define view ZCDS_ASS_02
as select from spfli as a
association [0..1] to sflight as _sflight
on $projection.carrierid = _sflight.carrid
and $projection.connid = _sflight.connid
{
key a.carrid as carrierid,
key a.connid,
a.cityfrom,
a.distance,
a.distid,
_sflight.fldate
}
where carrid = 'AA'
and connid = '0017'
按照以上逻辑在创建基数为[1..1],[0..5],[0..*]的CDS VIEW,以上结果都是一样的结果如下:
注意: 因为Association是按需Join,用不着Association的字段,就不会触发它,这样就有可能取到不同的结果,所以不同的基数写法会影响到使用这个CDS VIEW的报表结果
例子:
"基数[0..1]
SELECT carrierid AS carrid,
connid,
'[0..1]' AS cardinality,
SUM( distance ) AS distance
FROM zcds_ass_02
GROUP BY carrierid,connid
APPENDING TABLE @DATA(gt_a).
"基数[1..1]
SELECT carrierid AS carrid,
connid,
'[1..1]' AS cardinality,
SUM( distance ) AS distance
FROM zcds_ass_03
GROUP BY carrierid,connid
APPENDING TABLE @gt_a.
"基数[0..5]
SELECT carrierid AS carrid,
connid,
'[0..5]' AS cardinality,
SUM( distance ) AS distance
FROM zcds_ass_04
GROUP BY carrierid,connid
APPENDING TABLE @gt_a.
"基数[0..*]
SELECT carrierid AS carrid,
connid,
'[0..*]' AS cardinality,
SUM( distance ) AS distance
FROM zcds_ass_05
GROUP BY carrierid,connid
APPENDING TABLE @gt_a.
cl_demo_output=>display( gt_a ).
结果:
[0..1],[1..1]结果为:2572
[0..5],[0..*]结果为:2572 * 28
原因:因为前者只取1条,不需要触发association,join也就是没有发生。后者要取的条数大于1(虽然是5),触发了association,进行了join ,就会取所有的数据参与计算。
三、临时关联和公开关联
临时关联:
视图在元素列表中直接访问关联表/视图的字段
例子:
@AbapCatalog.sqlViewName: 'ZVCDS_ASS_TEST'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Association test'
define view ZCDS_ASS_TEST as select from spfli as a
association [0..*] to sflight as _sflight
on $projection.carrierid = _sflight.carrid
and $projection.connid = _sflight.connid
{
key a.carrid as carrierid,
key a.connid,
a.cityfrom,
a.cityto,
_sflight.fldate
}
Datebase Level的创建语句:
CREATE OR REPLACE VIEW "ZVCDS_ASS_TEST" AS SELECT
"A"."MANDT" AS "MANDT",
"A"."CARRID" AS "CARRIERID",
"A"."CONNID",
"A"."CITYFROM",
"A"."CITYTO",
"=A0"."FLDATE"
FROM "SPFLI" "A" LEFT OUTER MANY TO MANY JOIN "SFLIGHT" "=A0" ON (
"A"."CARRID" = "=A0"."CARRID" AND
"A"."CONNID" = "=A0"."CONNID" AND
"A"."MANDT" = "=A0"."MANDT"
)
从上面的Datebase Level的代码可以看出最终公开关联转换成了Left Outer Many To Many Join
默认情况下,Association相当于Left Outer Join / Left Outer To One Join取的结果
如果想结果为Inner join,如下图
公开关联:
将关联的别名本身放到元素列表中,而不是访问具体的字段。
先决条件:
打开关联使用的所有字段都必须是元素列表的一部分。
例子:
@AbapCatalog.sqlViewName: 'ZVCDS_ASS_TEST'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Association test'
define view ZCDS_ASS_TEST as select from spfli as a
association [0..*] to sflight as _sflight
on $projection.carrierid = _sflight.carrid
and $projection.connid = _sflight.connid
{
key a.carrid as carrierid,
key a.connid,
a.cityfrom,
a.cityto,
_sflight
}
Datebase Level的创建语句:
CREATE OR REPLACE VIEW "ZVCDS_ASS_TEST" AS SELECT
"A"."MANDT" AS "MANDT",
"A"."CARRID" AS "CARRIERID",
"A"."CONNID",
"A"."CITYFROM",
"A"."CITYTO"
FROM "SPFLI" "A"
在Database Level未做Join,需要触发关联才会Join
ABAP Open SQL访问CDS VIEW的Association里的字段
SELECT carrierid as carrid,
connid,
\_sflight-fldate
FROM zcds_ass_test
INTO TABLE @DATA(gt_a).
cl_demo_output=>display( gt_a ).
结果:
执行原理:
因为在执行的时候把Database Level的单独一个表的view转换成了Left Outer Join的View了,在SQL Trace里可以看到(T-CODE:ST05)
Fiori里如何访问Association
可以使用Expend如下:
var oModel = this.getOwnerComponent().getModel();
oModel.red("/zpersionSet(Persionid='00002')", {
urlParameters: {
$expand: "association 的名字,比如:_sflight",
},
success: function(odata) {
......................
},
error: function() {
......................
},
});
没环境就不展示了
四、路径表达式
作用:访问公开关联里的字段
定义一个新CDS VIEW 查询上面的ZCDS_ASS_TEST
例子:
@AbapCatalog.sqlViewName: 'ZVCDS_ASS_01'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Path Expressions Test'
define view zcds_ass_01
as select from ZCDS_ASS_TEST as A
{
key A.carrierid as carrid,
key A.connid,
/*这行就是路径表达式从公开关联中读取fldate*/
A._sflight.fldate as fldate,
_sflight
}
Database Level: