在路径表达式中使用关联
学习目标
在 CDS 视图中使用路径表达式。
在路径表达式中使用过滤条件。
在 ABAP SQL 中使用路径表达式。
CDS 中的路径表达式

CDS 视图实体从具有公开关联的实体读取时,有两种可能性:
传播关联
通过将关联名称添加到元素列表,关联也会对此视图的使用者可见。在示例中,关联 _Department 在视图实体 R_Employee 中定义和公开。视图实体 C_Employee 从 R_Employee 读取并传播关联 _Department。
使用关联
通过在关联名称后添加句点符号 (.) 和元素名称,关联用于从关联目标读取数据。这种用途称为路径表达式。在示例中,关联 _Department 的目标是 CDS 视图实体 C_Department。CDS 视图实体 C_Employee 使用路径表达式从关联目标中读取字段折旧指定,并将其添加到其自己的元素清单中。

在数据库级别,路径表达式将转换为关联源和关联目标的连接。这将在编辑器的 显示 SQL 创建语句 函数中可见。
在示例中,path expression _Department.DepmentSpecation 导致连接数据库中的 SQL 视图 R_EMPLOYEE 和 R_DEPARTMENT。连接的 ON 条件派生自关联的 ON 条件。
注意
连接类型 LEFT OUTER MANY TO ONE JOIN 是 SAP HANA 数据库的特殊类型。还有一种连接类型 LEFT OUTER MANY TO MANY JOIN,在关联基数的最大值大于 1 时使用。

需要强调的是,只有在路径表达式中使用关联时,才在数据库级别构建连接。定义、公开和传播关联不会导致联接。关联的此功能有时称为按需连接。
让我们再看一个示例:即使 CDS 视图实体 R_Employee 定义和公开关联 _Department 和 CDS 视图实体 C_Employee 传播此关联,相应的 SQL 视图 C_EMPLOYEE 也只能从 SQL 视图 R_EMPLOYEE 中读取。

到目前为止,我们仅使用一个关联讨论了路径表达式。但您还可以通过链接多个关联来构建更长的路径表达式。
以下是示例:CDS 视图实体 R_Employee 公开关联 _Department,其中将 CDS 视图实体 R_Department 作为目标。此目标公开另一个关联 _Head,指回到 R_Employee,但读取作为相应部门主管的员工。路径表达式 _Department。_Head.LastName 读取员工分配到的部门主管的姓氏。自动生成三个数据源的长而复杂的连接。

大多数情况下,CDS 视图实体定义关联时,会将其公开给其使用者。但是,它也可以直接使用 关联,而不是 ,或者除了公开它之外。
我们将此称为关联的即席使用。在示例中,CDS 视图实体 R_Employee 定义关联 _Department。它直接在路径表达式中使用关联来检索相关部门的指定,而不是公开关联。
如果是即席使用,则立即在此 CDS 视图实体的 SQL 视图中构建连接。
如何在 CDS 中写入路径表达式
播放视频,了解如何在 CDS 中编写路径表达式。
视频:本节含 SAP 官方视频(视频 ID
1_efp6bbxh),需在 learning.sap.com 在线观看。
基数对路径表达式的影响

在路径表达式中使用关联时,基数可能会影响语法检查。编辑器显示"对多"关联错误使用的警告,甚至错误,即基数最大值大于 1 的关联。
在视图定义的 WHERE 子句的路径表达式中,根本不允许使用"对多"关联,并会导致语法错误。
在元素列表中,允许"多个"关联,但编辑器会显示警告,指示此路径表达式可以修改结果集数。
此警告意味着什么?假设您的表仅包含 1 个具有 5 名员工的部门。如果没有路径表达式,CDS 视图 C_Department 仅返回 1 个数据集。然后将具有"多个"关联 _Employee 的路径表达式添加到元素列表。之后,同一视图返回 5 个数据集,每个员工一个。这可能会误导视图 C_Department 的消费者,因为他们期望每个部门有一个数据集。
提示
如果您对员工数据和部门数据的组合感兴趣,应从视图 R_Employee 开始,并使用 "to one" 关联 _Department 添加部门详细信息。

正确使用"对多"关联的一种方法是将路径表达式放置在聚合中。GROUP-BY-子句对于聚合是必需的,可确保数据集的数量保持不变。在此示例中,CDS 视图实体 C_Department 仍为每个部门返回一个数据集,而不是为每个员工返回一个数据集。
注意
正确使用"对多"关联的另一种方法是添加过滤条件。我们将在下一部分中讨论过滤器。
试用:错误且正确使用对多”关联
创建以 /DMO/I_Connection_R 作为参考数据对象的新 CDS 数据定义。
移除元素列表,包括花括号。
复制以下代码片段并将其插入到 as select from /DMO/I_Connection_R 之后:
{
key AirlineID,
key ConnectionID,
// _Airline.CurrencyCode,
// _Flight.PlaneType,
DepartureAirport,
DestinationAirport
}
where
AirlineID = 'LH' // Only one connection
and ConnectionID = '0400' // fulfills this filter
// and _Airline.CurrencyCode = 'EUR'
// and _Flight.PlaneType = '747-400'
激活数据定义并显示数据预览。由于 WHERE 子句完全限定了转机的主键,因此您只能看到一个数据集。
从元素列表中的两个路径表达式中移除注释标记。请注意语法警告,因为 _Flight 的基数为 0..* ,因此是"对多"关联。
尽管出现警告,但仍激活数据定义并显示数据预览。现在,您会看到多个数据集。
注释 WHERE 子句中的附加条件。请注意包含 _Flight 关联的路径表达式的语法错误。
移除元素列表和 WHERE 子句并将其替换为以下语法:
{
key AirlineID,
key ConnectionID,
_Flight.OccupiedSeats
// sum(_Flight.OccupiedSeats) as TotalOccupiedSeats
}
where
AirlineID = 'LH' // Only one connection
and ConnectionID = '0400' // fulfills this condition
// group by
// AirlineID,
// ConnectionID
请注意路径表达式(包括关联 _Flight )的语法警告。激活并显示数据预览。
注释掉路径表达式,并从集合函数 sum() 和 GROUP BY 子句中删除注释标记。请注意,语法警告已消失,并且数据预览仅显示一个数据集。
路径表达式中的过滤器

在路径表达式中使用关联时,可以添加过滤器以限制关联目标的数据集。过滤条件紧接在关联名称后面的一对方括号 ([ ]) 中。就像在 WHERE 子句中一样,您可以使用关系运算符和布尔运算符 AND、OR、NOT。条件的左侧必须是关联目标的字段。右侧具有更大的灵活性。此外,还可以使用关联目标、文字、内置函数等字段。
在此示例中,有两个路径表达式,一个没有过滤条件,另一个使用过滤条件 OccupiedSeats > MaximumSeats。第一个路径表达式搜索与转机相关联的最早航班,而第二个路径表达式将搜索限制为超额预订的航班,即已占用座位数超过可用座位数的航班。
从技术上讲,过滤条件将添加到数据库级别生成的连接的 ON 条件。
让我们看一下示例中的 SQL create 语句:示例中的第一个联接属于不含过滤器的路径表达式。ON 条件比较 AIRLINEID、CONNECTIONID 和客户端字段 MANDT。第二个联接属于具有 过滤器的路径表达式。是否可以从过滤的路径表达式中找出附加条件?

当您过滤基数最大大于 1 的关联时,可能会发生在应用过滤器后仅保留一个关联目标条目的情况。过滤器将"多个"关联转换为"对一"关联。在这种情况下,应在过滤条件前添加 "1: " 以记录关联的更改基数。
在此示例中,CDS 视图实体 I_Currency 定义和公开关联 _Text,这是"对多"关联,以不同语言返回货币名称。如果没有过滤器,关联将以系统中维护的所有语言读取货币的名称。但是,具有过滤器的两个路径表达式仅读取一个货币名称(英语或德语)。
如前所述,在聚合之外的路径表达式中使用"对多"关联时,语法检查会发出警告和错误。但是,如果过滤器确保只有一个记录,会发生什么?语法检查是否仍发出警告和错误?是的,这样做是因为它不知道过滤器将"多个"关联转换为"对一个"关联。我们可以通过在过滤器条件的方括号中添加 "1:" 来对此进行记录。在此示例中,对于过滤器为 Language = 'E' 的路径表达式,存在语法警告。但含过滤器 1: Language = 'D' 的路径表达式没有语法警告。
试用:过滤关联
创建以 /DMO/I_Connection_R 作为参考数据对象的新 CDS 数据定义。
移除元素列表,包括花括号。
复制以下代码片段并将其插入到 as select from /DMO/I_Connection_R 之后:
{
key AirlineID,
key ConnectionID,
//_Airline._Currency._Text.CurrencyName
//_Airline._Currency._Text[ Language = 'E' ].CurrencyName
//_Airline._Currency._Text[ 1: language = 'E' ].CurrencyName
}
where
AirlineID = 'AA'
and ConnectionID = '0017'
从第一个路径表达式中删除注释标记,并分析语法警告(如果有)。
为此版本的视图激活数据定义并显示数据预览和 SQL create 语句。
注释掉第一个路径表达式,并从第二个路径表达式中移除注释标记。
激活并分析包含过滤器的路径表达式的语法警告、数据预览和 SQL create 语句。
对第三个路径表达式重复上述步骤。
ABAP SQL 中的路径表达式

使用公开关联的另一种方法是使用 ABAP SQL 中的路径表达式。该概念与 CDS 中的概念完全相同,但语法略有不同。
最重要的语法区别如下:
关联前缀
在 ABAP SQL 路径表达式中,必须使用反斜线 () 对关联进行转义。
元素选择器
在 CDS 路径表达式中,句点 (.) 用作关联名称和元素名称之间的分隔符。在 ABAP SQL 中,期间符号不适用,因为它会结束语句。因此,在 ABAP SQL 中,连字符用作元素选择器。
让我们看一个示例:此 ABAP SQL SELECT 语句从公开关联 _Airline 的 CDS 视图实体 /DMO/I_Connection_R 中读取。FIELDS 列表中的最后一个表达式是从关联目标 /DMO/I_Carrier 中读取元素 Name 的路径表达式。

另一个语法差异与链接关联相关。当路径表达式包含关联序列时,没有专用分隔符。在 CDS 中,关联由句号 (.) 分隔,在 ABAP SQL 中彼此直接相邻。但请注意,每个关联名称都需要一个反斜线 () 作为前缀。
在此示例中,关联 _Airline 的目标公开返回航空公司本币详细信息的关联 _Currency。表达式 \_Airline\_Currency-CurrencyISOCode 读取经营转机的航空公司本币的 ISO 代码。
注意
在 CDS 中,相同的路径表达式为
_Airline._Currency.CurrencyISOCode。

在 ABAP SQL 中,筛选条件添加到方括号中,就像在 CDS 中一样。但是,要指定基数,将使用完全不同的语法。您必须添加关键字 MANY TO ONE WHERE,而不是 "1:"。还有其他几个选项,例如一个 TO ONE WHERE 和 MANY TO MANY WHERE。有关详细信息,请参阅 ABAP 关键字文档。
注意
存在一种替代语法,在其中编写 [ (1) WHERE … ] 而不是 [ MANY TO ONE WHERE … ],但不建议使用此替代语法。
试用:ABAP SQL 中的路径表达式
创建实施接口 IF_OO_ADT_CLASSRUN 的新全局类。
将以下代码片段复制到方法 if_oo_adt_classrun~main() 的实施部分:
* Data selection
**********************************************************************
SELECT FROM /dmo/i_connection_R
FIELDS Airlineid,
connectionid,
* _Airline.Name,
* \_Airline-Name,
* _Airline-Name,
* _Airline~Name,
* \_Airline~Name,
*
* \_Airline-_Currency-CurrencyISOCode,
* \_Airline-\_Currency-CurrencyISOCode,
* \_Airline\_Currency-CurrencyISOCode,
* \_Airline~\_Currency~CurrencyISOCode,
* \_Airline\_Currency~CurrencyISOCode,
*
* \_Airline\_Currency\_Text[ Language = 'E' ]-CurrencyShortName AS CurrencyNameEN,
* \_Airline\_Currency\_Text[ MANY TO ONE WHERE Language = 'D' ]-CurrencyShortName AS CurrencyNameDE,
* \_Airline\_Currency\_Text[ Language = 'E' ]-CurrencyShortName AS CurrencyNameEN,
* \_Airline-\_Currency-\_Text[ MANY TO ONE WHERE Language = 'D' ]-CurrencyShortName AS CurrencyNameDE,
* \_Airline~\_Currency~\_Text[ 1: Language = 'E' ]-CurrencyShortName AS CurrencyNameEN,
DepartureAirport,
DestinationAirport
INTO TABLE @DATA(result).
* Output
**********************************************************************
out->write( data = result
name = 'Selection result').
此编码包含带有各种路径表达式的 ABAP SQL SELECT 语句。 3. 从路径表达式的第一个块中移除注释,并使用语法检查查找 ABAP SQL 中语法正确的路径表达式。 4. 移除语法错误的变式,激活类,将其作为控制台应用执行,并分析控制台输出。 5. 对第二个和第三个路径表达式块重复此操作。
在路径表达式中使用关联
您已定义具有公开关联的 CDS 视图实体。您想要使用公开的关联。首先在 CDS 视图中执行此操作,然后在 ABAP SQL 的 SELECT 语句中执行此操作。
模板:
/LRN/CL_S4D430_RLT_PATH_EXP(全局类)
解决方案:
/LRN/C_EMPLOYEE_QRY(数据定义)
/LRN/CL_S4D430_RLS_PATH_EXP(全局类)
任务 1: 在 CDS 中使用公开关联
定义新的 CDS 视图实体(建议名称:Z##_C_EmployeeQuery)。使用公开关联的员工数据的视图实体作为数据源(建议名称为 Z##_R_Employee)。在元素清单中,读取员工标识和姓名。然后,添加路径表达式以读取部门描述和部门助理的姓氏。
注意
如果尚未完成上一练习,则可以让新的视图实体从 /LRN/R_Employee_Rel 视图实体中读取。
步骤
在您自己的包中,创建新的数据定义(建议名称:
Z##_C_EMPLOYEEQUERY,其中##是您的组编号)。指定 CDS 视图实体Z##_R_Employee作为参考对象,然后选择定义视图实体模板以生成定义语句、某些标准注释和元素列表。在项目浏览器视图中,右键单击数据定义
Z##_R_EMPLOYEE以打开上下文菜单。从上下文菜单中,选择新建数据定义。
确认包字段包含包的名称,并且参考对象字段包含数据库表定义的名称。
在名称字段中,输入 CDS 视图实体的名称(
Z##_C_EmployeeQuery,其中 ## 是您的组编号)。在描述字段中输入**
员工(查询)**,然后选择下一步。确认传输请求,然后选择下一步。
警告
确保尚未选择完成。如果执行此操作,则无法选择要使用的模板。
从模板列表中,选择定义视图实体,然后选择完成。
应用源代码格式设置。
从 eclipse 菜单中选择 源代码→格式 。或者,选择
Shift + F1。编辑新数据定义的元素列表。移除除
EmployeeID、FirstName、LastName、DepartmentID和公开关联_Department之外的所有元素。如下调整代码:
define view entity Z##_C_EmployeeQuery
as select from Z##_R_Employee
{
key EmployeeId,
FirstName,
LastName,
DepartmentID,
/* Associations */
_Department
}
在
DepartmentID元素之后,添加路径表达式以读取员工分配到的部门的描述(建议元素名称:DepartmentDescription)。如下调整代码:
define view entity Z##_C_EmployeeQuery
as select from Z##_R_Employee
{
key EmployeeId,
FirstName,
LastName,
DepartmentID,
_Department.Description as DepartmentDescription,
/* Associations */
_Department
}
保存数据定义并显示 SQL CREATE 语句。
注意
如果不保存数据定义,您的更改将不会出现在 SQL CREATE 语句中。
按
Ctrl + S保存开发对象。右键单击数据定义源代码中的任意位置,然后选择显示 SQL CREATE 语句。
添加路径表达式以读取部门助理的姓氏(建议元素名称:
AssistantName)。如下调整代码:
define view entity Z##_C_EmployeeQuery
as select from Z##_R_Employee
{
key EmployeeId,
FirstName,
LastName,
DepartmentID,
_Department.Description as DepartmentDescription,
_Department._Assistant.LastName as AssistantName,
/* Associations */
_Department
}
激活数据定义并再次显示 SQL CREATE 语句。
按
Ctrl + F3激活开发对象。右键单击数据定义源代码中的任意位置,然后选择显示 SQL CREATE 语句。
在数据预览工具中显示查询结果。
将光标放在数据定义中的任意位置,然后按
F8调用数据预览工具。
任务 2: 在 ABAP SQL 中使用公开关联
创建 ABAP 类 /LRN/CL_S4D430_RLT_PATH_EXPR(建议名称:ZCL_##_PATH_EXPR)的副本并调整 SELECT 语句。从刚创建的 CDS 视图实体(建议名称为 Z##_C_EmployeeQuery)中读取所有字段。此外,在 ABAP SQL 中实施路径表达式以读取部门主管的名称。
步骤
将
/LRN/CL_S4D430_RLT_PATH_EXPR类复制到您自己的包中的类(建议名称:ZCL_##_PATH_EXPR,其中 ## 代表组编号)。在项目浏览器视图中,右键单击
/LRN/CL_S4D430_RLT_PATH_EXP类以打开上下文菜单。从上下文菜单中,选择复制 ....
在包字段中输入包的名称。在名称字段中,输入名称
ZCL_##_PATH_EXP,其中 ## 是您的组编号。调整描述,然后选择下一步。
确认传输请求并选择完成。
在
IF_OO_ADT_CLASSRUN~MAIN方法中,更改 SELECT 语句。将 FROM 子句中的/LRN/C_Employee_Ann替换为您刚刚创建的 CDS 视图实体的名称 (Z##_C_EmployeeQuery)。如下调整代码:
SELECT
FROM Z##_C_EmployeeQuery
FIELDS employeeid,
在字段清单末尾,还可以读取新视图元素
DepartmentDescription和AssistantName。如下调整代码:
SELECT
FROM Z##_C_EmployeeQuery
FIELDS employeeid,
firstname,
lastname,
departmentid,
departmentdescription,
assistantname
INTO TABLE @DATA(result).
在部门助理的姓名之后,实施读取部门主管姓氏的路径表达式(建议字段名称:
HEADNAME)。
提示
尽可能使用代码完整化。请记住,在 ABAP SQL 中,关联名称需要反斜线符号 () 作为前缀,并在关联名称和元素名称之间使用破折号 (-)。
如下调整代码:
SELECT
FROM Z##_C_EmployeeQuery
FIELDS employeeid,
firstname,
lastname,
departmentid,
departmentdescription,
assistantname,
\_department\_head-lastname AS headname
INTO TABLE @DATA(result).
激活全局类并将其作为控制台应用执行。
按
Ctrl + F3激活开发对象。按
F9将全局类作为控制台应用执行。