在 ABAP SQL 中排序和压缩数据集

学习目标

  • 从数据库请求排序的结果集。

  • 检索压缩数据集和聚合数据集。

排序的结果集

在本视频中,您将了解如何对 SELECT 语句的结果集进行排序。

视频:本节含 SAP 官方视频(视频 ID 1_dp1fdf52),需在 learning.sap.com 在线观看。

试用:ORDER BY

  1. 创建实施接口 IF_OO_ADT_CLASSRUN 的新全局类。

  2. 将以下代码片段复制到方法 if_oo_adt_classrun~main() 的实施部分:

SELECT FROM /dmo/flight
FIELDS carrier_id,
connection_id,
flight_date,
seats_max - seats_occupied AS seats
WHERE carrier_id     = 'AA'
AND plane_type_id  = 'A320-200'
*       ORDER BY seats_max - seats_occupied DESCENDING,
*                flight_date                ASCENDING
INTO TABLE @DATA(result).
out->write(
EXPORTING
data   = result
name   = 'RESULT'
).
  1. 选择 CTRL + F3 激活类,然后选择 F9 将其作为控制台应用执行。

  2. 分析控制台输出。

  3. 使用 ORDER BY 附加项移除行中的星号 (*),然后再次激活。

  4. 再次执行 并查看控制台输出的排序顺序如何更改。

  5. 使用 ORDER BY 附加功能进行导航。更改排序方向,按其他字段或表达式对结果进行排序以熟悉语法。

唯一结果集

附加项 DISTINCT 允许您从 SELECT 语句的结果集中删除重复项。附加必须放在字段列表第一个元素的前面。

观看此视频,了解如何操作。

视频:本节含 SAP 官方视频(视频 ID 1_0ipn4c81),需在 learning.sap.com 在线观看。

试用:SELECT DISTINCT

  1. 创建实施接口 IF_OO_ADT_CLASSRUN 的新全局类。

  2. 将以下代码片段复制到方法 if_oo_adt_classrun~main() 的实施部分:

SELECT FROM /dmo/connection
FIELDS
*           DISTINCT
airport_from_id,
distance_unit
ORDER BY airport_from_id
INTO TABLE @DATA(result).
out->write(
EXPORTING
data   = result
name   = 'RESULT'
).
  1. 选择 CTRL + F3 激活类,然后选择 F9 将其作为控制台应用执行。

  2. 分析控制台输出。

  3. 移除带有 DISTINCT 附加项的行中的星号 (*),然后再次激活。

  4. 再次执行 并查看控制台输出如何更改。

集合函数

集合表达式通过对结果集的多行调用集合函数,从 sql_expression (sql_exp) 计算单个值。

一些重要的聚合函数包括:

  • SUM( sql_exp) 确定行集中 SQL 表达式 sql_exp 的结果总和。结果集的数据类型是 SQL 表达式的类型。SQL 表达式 sql_exp 的结果类型必须是数值类型。

  • MIN( sql_exp) 和 MAX( sql_exp ) 确定行集中 SQL 表达式 sql_exp 结果的最大值或最小值。结果的数据类型是 SQL 表达式的结果类型。 SQL 表达式 sql_exp 的结果必须是数值类型。如果为表达式指定了单个列,则此列也可以具有任何数据类型。

  • AVG( sql_exp [ AS dtype ] ) 确定行集中 SQL 表达式 sql_exp 内容的平均值。十进制浮点数结果的隐式数据类型是相应的数据类型(DECFLOAT16 或 DECFLOAT34 或 DF16_DEC 或 DF34_DEC),否则为 FLTP 类型,或由附加项 AS 数据类型确定。

  • COUNT( ) 或 COUNT() 这两个拼写具有相同的含义,并生成行集中的行数。大多数情况下,结果类型为 INT4。如果 COUNT( ) 或 COUNT() 是字段列表中的唯一元素,则结果类型为 INT8。

  • COUNT( DISTINCT sql_exp ) 确定行集中 SQL 表达式 sql_exp 结果的非重复值数量。结果的数据类型为 INT4。

仅字段清单中的聚合功能

如果 SELECT 语句的字段列表仅包含集合函数,则结果集始终仅包含一行。请注意,如果聚合基于空数据集,也是如此。

在我们的示例中,左侧的 SELECT 语句说明了右侧 SELECT 中的聚合所基于的数据集。

您可以看到 DISTANCE 列中的最大值为 6217,而最小值为 6162。总行数为 4,列 AIRPORT_FROM_ID 包含 3 个非重复值(值 'FRA' 出现两次)。

试用:聚合函数

  1. 创建实施接口 IF_OO_ADT_CLASSRUN 的新全局类。

  2. 将以下代码片段复制到方法 if_oo_adt_classrun~main() 的实施部分:

SELECT FROM /dmo/connection
FIELDS carrier_id,
connection_id,
airport_from_id,
distance
WHERE carrier_id = 'LH'
INTO TABLE @DATA(result_raw).
out->write(
EXPORTING
data   = result_raw
name   = 'RESULT_RAW'
).
*********************************************************************
SELECT FROM /dmo/connection
FIELDS MAX( distance ) AS max,
MIN( distance ) AS min,
SUM( distance ) AS sum,
AVG( distance ) AS average,
COUNT( * ) AS count,
COUNT( DISTINCT airport_from_id ) AS count_dist
WHERE carrier_id = 'LH'
INTO TABLE @DATA(result_aggregate).
out->write(
EXPORTING
data   = result_aggregate
name   = 'RESULT_AGGREGATED'
).
  1. 选择 CTRL + F3 激活类,然后选择 F9 将其作为控制台应用执行。

  2. 分析控制台输出。

GROUP BY 附加项

如果 SELECT 语句的字段列表包含集合函数和其它元素(如列、表达式等)的混合,则 SQL 的语法需要 GROUP BY 子句。GROUP BY 子句必须列出聚合之外的字段列表中显示的所有列。

在右侧的 SELECT 语句中,字段列表中使用两列:CARRIER_ID 和 DISTANCE。列 DISTANCE 只显示为集合函数的输入,因此在 GROUP BY 之后不是必需的。但列 CARRIER_ID 在聚合函数之外使用,因此必须在 GROUP BY 之后列出。

GROUP BY 的影响可以在 SELECT 语句的结果中看到。执行聚合的数据集分为在 GROUP BY - 字段中具有相同值的子集(组)。每个组在最终结果集中都有相应的一行。针对每个组分别对集合表达式求值。

例如,CARRIER_ID = 'AA' 的行包含 COUNT = 5 和 MAX = 4156,因为 CARRIER_ID = 'AA' 的子集包含 5 行,而此子集中距离的最大值为 4156。

试用:GROUP BY

  1. 创建实施接口 IF_OO_ADT_CLASSRUN 的新全局类。

  2. 将以下代码片段复制到方法 if_oo_adt_classrun~main() 的实施部分:

SELECT FROM /dmo/connection
FIELDS
*            carrier_id,
MAX( distance ) AS max,
MIN( distance ) AS min,
SUM( distance ) AS sum,
COUNT( * ) AS count
*     GROUP BY carrier_id
INTO TABLE @DATA(result).
out->write(
EXPORTING
data   = result
name   = 'RESULT'
).
  1. 选择 CTRL + F3 激活类,然后选择 F9 将其作为控制台应用执行。

  2. 分析控制台输出。

  3. 移除带有关键字 FIELDS 的行(字段名称为 carrier_id 的行)后行中的星号 (*)。请注意语法错误,告知您字段 CARRIER_ID 在 GROUP BY 子句中缺失。

  4. 从带有 GROUP BY 附加的行中移除星号 (*),然后再次激活。

  5. 再次执行 并查看控制台输出如何更改。

检索排序和聚合数据

在本练习中,按日期对航班进行排序,并计算数据库中航班的平均占用率。

模板:

  • /LRN/CL_S4D401_DBS_FUNCTIONS(全局类)

解决方案:

  • /LRN/CL_S4D401_DBS_AGGREGATE(全局类)

任务 1: 复制模板(可选)

复制模板类 /LRN/CL_S4D401_DBS_FUNCTIONS。如果已完成上一练习,则可以跳过此任务并继续编辑类 ZCL_##_SOLUTION

步骤

  1. 将类 /LRN/CL_S4D401_DBS_FUNCTIONS 复制到您自己的包中的类(建议名称:ZCL_##_SOLUTION,其中 ## 代表组编号)。

  2. 在项目浏览器中,右键单击类 /LRN/CL_S4D401_DBS_FUNCTIONS 以打开上下文菜单。

  3. 从上下文菜单中,选择复制....

  4. 在包字段中输入的名称。在名称字段中,输入 ZCL_##_SOLUTION,其中 ## 代表组编号。

  5. 选择下一步

  6. 确认传输请求并选择完成

  7. 激活复制。

  8. Ctrl + F3 激活类。

任务 2: 排序数据

在局部类 LCL_PASSENGER_FLIGHT 中,调整方法 GET_FLIGHTS_BY_CARRIER 的实施。添加合适的指令,以按升序检索按航班日期排序的航班列表。然后在本地类 LCL_CARGO_FLIGHT 中执行相同操作。

步骤

  1. 在局部类 LCL_PASSENGER_FLIGHT 中,导航至方法 GET_FLIGHTS_BY_CARRIER 的实施。

  2. 照常执行该步骤。

  3. 调整 SELECT 语句以确保数据库返回按航班日期升序排序的结果。

  4. 在 INTO 子句之前添加 ORDER BY 子句。

  5. 如下调整代码:

SELECT
FROM /lrn/passflight
FIELDS carrier_id, connection_id, flight_date,
plane_type_id, seats_max, seats_occupied,
seats_max - seats_occupied AS seats_free,
currency_conversion(
amount             = price,
source_currency    = currency_code,
target_currency    = @currency,
exchange_rate_date = flight_date,
on_error           =
@sql_currency_conversion=>c_on_error-set_to_null
) AS price,
@currency AS currency_code
WHERE carrier_id = @i_carrier_id
ORDER BY flight_date ASCENDING
INTO TABLE @flights_buffer.
  1. 导航到本地类 LCL_CARGO_FLIGHT 中的方法 GET_FLIGHTS_BY_CARRIER

  2. 照常执行该步骤。

  3. 调整 SELECT 语句以确保数据库返回按航班日期升序排序的结果。

  4. 在 INTO 子句之前添加 ORDER BY 子句。

  5. 如下调整代码:

SELECT
FROM /lrn/cargoflight
FIELDS carrier_id, connection_id, flight_date,
plane_type_id, maximum_load, actual_load, load_unit,
airport_from_id, airport_to_id, departure_time, arrival_time
WHERE carrier_id = @i_carrier_id
ORDER BY flight_date ASCENDING
INTO CORRESPONDING FIELDS OF TABLE @flights_buffer.

任务 3: 使用聚合函数

在局部类 LCL_CARRIER 中,调整方法 GET_AVERAGE_FREE_SEATS 的实施。使用数据库表 /LRN/PASSFLIGHT 中的 SELECT 进行计算,而不是计算所有乘客航班循环中的结果。

步骤

  1. 在局部类 LCL_CARRIER 中,导航到方法 GET_AVERAGE_FREE_SEATS 的实施。

  2. 照常执行该步骤。

  3. 删除或注释方法实施的源代码。

  4. 标记语句 METHOD get_average_free_seats.ENDMETHOD. 之间的代码,然后按 Ctrl + <

  5. 现在,实施一个 SELECT 语句,该语句检索当前航空公司(存储在 carrier_id 属性中)的可用座位和乘客航班总数。将结果存储在内联声明的数据对象中(建议名称:聚合)。

  6. 添加以下代码:

SELECT FROM /lrn/passflight
FIELDS SUM( seats_max - seats_occupied ) AS sum,
COUNT(*) AS count
WHERE carrier_id = @carrier_id
INTO @DATA(aggregates).
  1. 在 SELECT 语句之后,计算两个集合的比率,并将结果指派给返回参数 r_result

  2. 如下调整代码:

SELECT FROM /lrn/passflight
FIELDS SUM( seats_max - seats_occupied ) AS sum,
COUNT(*) AS count
WHERE carrier_id = @carrier_id
INTO @DATA(aggregates).
r_result = aggregates-sum / aggregates-count.

注意

可以通过以下代码实现 GET_AVERAGE_FREE_SEATS 方法的更简要实施:

abap SELECT FROM /lrn/passflight FIELDS CAST( AVG( seats_max - seats_occupied ) AS INT4 ) WHERE carrier_id = @carrier_id INTO @r_result.

  1. 以控制台应用形式激活并测试全局类。

  2. Ctrl + F3

  3. F9