ABAP猿个人技术分享$ ABAP猿个人技术分享

ABAP CTE(Common Table Expressions)完全指南 —— 让你的 SQL 查询更简洁、更强大

2 次阅读#CTE
ABAP CTE(Common Table Expressions)完全指南 —— 让你的 SQL 查询更简洁、更强大

一、什么是 CTE?

CTE(Common Table Expression,公共表表达式) 是 SQL 标准中的一个特性,ABAP 从 7.55 版本开始支持。它允许你在一条 SQL 语句中用 WITH 关键字定义一个或多个临时的命名结果集,并在后续的查询中像使用普通表一样引用它们。

版本要求

环境 最低版本
SAP S/4HANA On-Premise ABAP 7.55 (SAP S/4HANA 2020)
SAP BTP ABAP Environment 2102
SAP HANA Database HANA 2.0 SPS 04+

基本语法

WITH
  +cte_name1 AS ( SELECT ... ),
  +cte_name2 AS ( SELECT ... FROM +cte_name1 ... )
  SELECT ... FROM +cte_name2 ...
  INTO TABLE @DATA(result).

核心规则:

  • 每个 CTE 名称前必须加 + 前缀
  • 多个 CTE 之间用逗号分隔
  • CTE 可以引用它之前定义的 CTE
  • 最后一个 SELECT 负责消费 CTE 并写出最终结果

二、为什么需要 CTE?

在 CTE 出现之前,ABAP 开发者通常用嵌套子查询多步临时表来处理复杂查询。CTE 带来了三个关键改进:

2.1 可读性提升

嵌套子查询往往"从内向外"阅读,而 CTE "从上向下"阅读,更符合人的思维习惯。

2.2 复用性

同一个 CTE 可以在后续查询中被多次引用,避免重复编写相同的子查询。

2.3 递归查询

CTE 支持自引用,可以进行递归查询处理层次化数据(如 BOM 展开、组织架构树)。


三、实战示例

以下示例基于 SAP Flight 演示数据模型(SCARR 航空公司表、SPFLI 航班计划表、SFLIGHT 航班表)。

示例数据:系统中 SCARR 表有 18 条航空公司记录,SPFLI 表包含全球 26 条航线,SFLIGHT 表包含各航班的执飞明细。

3.1 基础 CTE:单层筛选

场景:查询 Lufthansa(LH)航空公司的所有航班信息。

WITH
  +flights AS (
    SELECT carrid, connid, fldate, price, seatsocc
    FROM sflight
    WHERE carrid = 'LH'
  )
  SELECT carrid, connid, fldate, price, seatsocc
  FROM +flights
  INTO TABLE @DATA(lt_result)
  UP TO 10 ROWS.

语法要点:CTE 的定义用 AS ( SELECT ... ) 包裹,引用时用 FROM +cte_name

3.2 多重 CTE:链式处理

场景:先筛选出 LH 的航班,再对筛选结果做聚合统计。

WITH
  +lh_flights AS (
    SELECT carrid, connid, fldate, price, seatsocc, seatsmax
    FROM sflight
    WHERE carrid = 'LH'
  ),
  +flight_stats AS (
    SELECT carrid, connid,
           COUNT(*) AS flight_count,
           AVG( price AS DEC(15,2) ) AS avg_price,
           SUM( seatsocc ) AS total_occ
    FROM +lh_flights
    GROUP BY carrid, connid
  )
  SELECT carrid, connid, flight_count, avg_price, total_occ
  FROM +flight_stats
  ORDER BY carrid, connid
  INTO TABLE @DATA(lt_stats)
  UP TO 20 ROWS.

语法要点:第二个 CTE +flight_stats 引用了第一个 CTE +lh_flights。CTE 可以链式引用,但不能引用尚未定义的 CTE。

3.3 CTE + JOIN:关联查询

场景:查询远程航线(距离 > 1000 公里),并关联航空公司名称。

WITH
  +route_summary AS (
    SELECT spfli~carrid, spfli~connid,
           spfli~cityfrom, spfli~cityto,
           spfli~distance, spfli~fltime
    FROM spfli
    WHERE spfli~distance > 1000
  ),
  +long_routes AS (
    SELECT rs~carrid, rs~connid,
           rs~cityfrom, rs~cityto,
           rs~distance, rs~fltime,
           scarr~carrname
    FROM +route_summary AS rs
    INNER JOIN scarr ON scarr~carrid = rs~carrid
  )
  SELECT carrname, connid, cityfrom, cityto, distance, fltime
  FROM +long_routes
  ORDER BY distance DESCENDING
  INTO TABLE @DATA(lt_routes)
  UP TO 10 ROWS.

语法要点:CTE 可以与普通表做 JOIN。给 CTE 加别名(AS rs)可以让 JOIN 条件更清晰。

3.4 聚合 CTE:统计分析

场景:统计每家航空公司的航线数量、航班总数、平均票价和总载客量。

WITH
  +carrier_stats AS (
    SELECT sflight~carrid,
           COUNT( DISTINCT sflight~connid ) AS route_cnt,
           COUNT(*) AS total_flights,
           AVG( sflight~price AS DEC(15,2) ) AS avg_price,
           SUM( sflight~seatsocc ) AS total_pax
    FROM sflight
    GROUP BY sflight~carrid
  )
  SELECT scarr~carrname, cs~route_cnt, cs~total_flights,
         cs~avg_price, cs~total_pax
  FROM +carrier_stats AS cs
  INNER JOIN scarr ON scarr~carrid = cs~carrid
  ORDER BY cs~total_pax DESCENDING
  INTO TABLE @DATA(lt_carrier_stats)
  UP TO 10 ROWS.

语法要点COUNT( DISTINCT ... )AVG( ... AS DEC(15,2) ) 都在 CTE 内部完成,主查询只需做简单的 JOIN 和排序。

3.5 业务分析 CTE:高负载航班

场景:找出客座率超过 80% 的高负载航班。

WITH
  +all_flights AS (
    SELECT sflight~carrid, sflight~connid, sflight~fldate,
           sflight~price, sflight~seatsocc, sflight~seatsmax
    FROM sflight
  ),
  +high_load AS (
    SELECT carrid, connid, fldate, price, seatsocc, seatsmax
    FROM +all_flights
    WHERE seatsocc * 100 / seatsmax > 80
  )
  SELECT scarr~carrname, hl~connid, hl~fldate,
         hl~price, hl~seatsocc, hl~seatsmax
  FROM +high_load AS hl
  INNER JOIN scarr ON scarr~carrid = hl~carrid
  ORDER BY hl~fldate DESCENDING
  INTO TABLE @DATA(lt_high_load)
  UP TO 10 ROWS.

语法要点:在 CTE 中计算百分比并做筛选,将复杂的计算逻辑和过滤逻辑分离,代码意图一目了然。


四、CTE vs 子查询 vs 临时表

特性 CTE (WITH) 嵌套子查询 临时表 (INTO)
可读性 高,自上而下 低,自内向外
复用性 可在同一 SQL 中多次引用 需重复编写 可跨语句使用
性能 优化器处理,不物化 优化器处理 物理存储
递归支持 支持 不支持 需循环实现
作用域 当前 SQL 语句 当前子查询 当前程序

五、注意事项与限制

5.1 作用域限制

CTE 仅在当前 SQL 语句中有效。语句执行完毕后 CTE 即消失,不能被其他 SQL 语句引用。

5.2 不支持 INSERT/UPDATE/DELETE

CTE 只能用于 SELECT 查询,不能用于数据修改操作。

5.3 CTE 名称规则

CTE 名称必须以 + 开头,命名遵循 ABAP 命名规范(建议使用有意义的英文名称)。

5.4 性能考量

CTE 不会被物化(materialize),每次引用 CTE 时,数据库优化器会将其内联展开。对于复杂的 CTE,如果被多次引用,可能导致重复计算。在这种情况下,可以考虑先 SELECT ... INTO TABLE 存入内表。

5.5 递归 CTE

ABAP 7.57 开始支持递归 CTE(自引用 + UNION),适用于处理层次化数据。后续会单独写一篇递归 CTE 的专题文章。


六、总结

要点 说明
是什么 WITH 关键字定义的临时命名结果集
语法核心 +cte_name AS ( SELECT ... )
主要优势 可读性 好、复用性强、支持递归
适用场景 多步骤数据筛选、复杂聚集、层次遍历
版本要求 ABAP 7.55+

CTE 并不是什么"新玩具",而是一个真正能减少代码复杂度、提高 SQL 可维护性的实用特性。如果你正在使用 ABAP 7.55 及以上版本,强烈建议将 CTE 纳入你的 SQL 工具箱。


本文所有代码示例基于 SAP S/4HANA ABAP 7.55+ 语法规范,使用 SAP Flight 演示数据模型(SCARR、SPFLI、SFLIGHT)编写。

评论

还没有评论,来说两句吧。