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)编写。
评论
还没有评论,来说两句吧。