Open SQL 关键字:WITH
Open SQL 语句。引入一个或多个通用表表达式 +cte1、+cte2 的定义,用于关闭主查询 SELECT … 通用表表达式的结果集由子查询子查询决定。
通用表表达式(common table expression)
通用表表达式(简称 CTE)在 Open SQL 语句 WITH
中使用子查询进行定义。WITH
语句的主查询访问通用表表达式。
语法:
WITH
+cte1[( name1, name2, ... )] AS ( SELECT subquery_clauses [UNION ...] )[,
+cte2[( name1, name2, ... )] AS ( SELECT subquery_clauses [UNION ...] ),
... ]
SELECT mainquery_clauses
[UNION ...]
INTO|APPENDING target
[additional_options].
...
[ENDWITH].
WITH
引入了在最终主查询中使用的通用表表达式(简称 CTE)的定义。WITH 可以作为独立语句使用(如图所示),也可以在 OPEN CURSOR 语句之后使用。
每个通用表达式都会在子查询中创建一个表格结果集,该结果集可作为数据源 data_source 用于 WITH
语句的后续查询。
WITH
语句由以下部分组成:
- 以逗号分隔的列表,其中包含至少一个通用表表达式定义
- 每个通用表达式都有一个唯一的名称 +cte1、+cte2、…。名称 cte 最多可以有 30 个字符,可以包含字母、数字和下划线。它们必须以字母或下划线开头。此外,名称的前缀必须是 + 字符。首字母 + 字符是名称的一部分,但不能单独存在,后面也不能有数字。
- 可以在名称后直接指定一个可选的名称列表(name1、name2、…),用于指定通用表表达式结果集的列名(见下文)。
- 在
AS
后面有一个带括号的子查询SELECT
subquery_clauses。该子查询创建通用表表达式的表格结果集。语言元素UNION
可用来组合多个子查询的结果集。在这种情况下,附加规则 query_clauses 适用于指定子查询。
- 封闭式主查询
SELECT
mainquery_clauses,它可以包含与独立 SELECT 语句相同的子句和添加内容(FOR ALL ENTRIES
除外),工作方式也相同:- 主查询的结果集根据
INTO
子句分配给 ABAP 数据对象。 - 如
SELECT
中所述,创建单行或多行结果集,并根据INTO
子句中指定的目标区域,打开或不打开SELECT
循环。 - SELECT 循环必须以
ENDWITH
语句结束。对于WITH ... SELECT
时,ENDWITH
与独立SELECT
循环的ENDSELECT
意义完全相同。 - 在主查询中,之前定义的每个通用表表达式 +cte1、+cte2 等都可用作数据源 data_source。
- 主查询的结果集根据
语言元素 UNION
可用来组合多个主查询的结果集。在这种情况下,附加的 query_clauses 规则适用于指定子句。
在 WITH
语句中定义的通用表表达式在定义后可以在另一个共用表表达式的子查询中使用,并在主查询中作为数据源 data_source 使用。它不能在自己的子查询中使用,也不能在前面定义的子查询中使用。通用表表达式只能在当前 WITH
语句中使用。
WITH
语句中定义的每个通用表表达式必须在 WITH
语句中至少使用一次,可以在另一个通用表表达式中使用,也可以在主查询中使用。也就是说,主查询必须访问至少一个通用表表达式。
通用表表达式的名称 +cte 在整个 WITH
语句中有效。只有在 INTO
子句中将子结构创建为通用表表达式的数据源时,子结构名称中的 + 字符才会被省略。
通用表表达式的结果集永远不会 client 列。即使在子查询中将客户专用数据源的客户列明确添加到其 SELECT
列表中,在结果集中也不会有客户列。因此,在使用普通表表达式作为数据源的 WITH
语句查询中,不能指定添加 CLIENT SPECIFIED
。
Notes:
- 通用表表达式会创建一个临时表格结果集,可在执行 WITH 语句期间访问该结果集。因此,可以将通用表表达式视为临时视图,它只在数据库访问期间存在。
- 只要 SELECT 语句中需要小计,就可以使用通用表表达式。如果使用通用表表达式,开放式 SQL 语句的可读性会更高,而且如果需要多次使用小计,通用表表达式总是很有用。如果需要,通用表表达式还可以执行 GTTs 的任务。
- 使用通用表表达式还可以直接从子查询
SELECT FROM
子查询中进行选择,这在 Open SQL 中是不可能实现的。 - 作为前缀的字符 + 将表表达式标记为通用表表达式,就像主机变量的字符 @ 一样。字符 + 可以防止通用表表达式与 ABAP 字典中的表具有相同的名称,从而使其模糊不清。
- 对于用
ENDWITH
结束的WITH
循环,与SELECT
循环的注意事项相同。特别是,WITH
循环不应嵌套。 - 在
WITH
语句的查询中可以添加CLIENT SPECIFIED
(客户指定的数据源),以停用客户自动处理功能。 - 在
WITH
语句的主查询中,如果在SELECT
列表中指定了 *,则表示没有未转换的数据传输到 INTO 后指定的工作区 - WITH 语句绕过了 SAP 缓冲。
- 如果使用 WITH 语句,语法缓冲将在 7.51 版的严格模式下执行。
示例
通用表表达式 +cities 的结果集是航空公司飞往或飞离的所有城市的列表。通用表表达式在主查询中用作 WHERE 条件子查询的数据源。
DATA carrid TYPE spfli-carrid VALUE 'LH'.
cl_demo_input=>request( CHANGING field = carrid ).
WITH
+cities AS (
SELECT cityfrom AS city
FROM spfli
WHERE carrid = @carrid
UNION DISTINCT
SELECT cityto AS city
FROM spfli
WHERE carrid = @carrid )
SELECT *
FROM sgeocity
WHERE city IN ( SELECT city
FROM +cities )
INTO TABLE @DATA(result).
cl_demo_output=>display( result ).
… ( name1, name2, … )
定义通用表表达式 +cte 的列名。指定的名称 name1、name2… 将按给定的顺序分配给通用表表达式子查询 SELECT 列表中定义的列。这些名称的作用类似于使用 AS 在 SELECT 列表中定义的替代列名,并会覆盖这些名称。
- 如果指定了名称列表,该列表必须包含通用表表达式中每一列的名称
- 如果没有指定名称列表,则结果列表中的列将使用子查询 SELECT 列表中定义的名称。
开头括号必须直接位于 +cte1、+cte2 等名称之后。在开头括号之后和结尾括号之前必须至少有一个空格。逗号分隔的名称列表中可以有空白。
名称最多可以有 30 个字符,可以包含字母、数字和下划线。名称必须以字母或下划线开头。
注意:
如果在子查询的 SELECT 列表中选择了所有带 *
的列,则可以指定名称列表。如果扩展子查询的数据源,这可能会导致语法错误。
示例:
通用表表达式 +connections 和 +sum_seats 的结果集在通用表表达式 +result 的子查询中合并为一个连接表达式。显式名称列表为结果列分配名称。这些名称在主查询中用于对结果进行排序。对于所选航空公司的每个航班连接,占用座位总数将从数据库表 SFLIGHT
中输出。
DATA from_id TYPE spfli-carrid VALUE 'AA'.
cl_demo_input=>add_field( CHANGING field = from_id ).
DATA to_id TYPE spfli-carrid VALUE 'UA'.
cl_demo_input=>request( CHANGING field = to_id ).
from_id = to_upper( from_id ).
to_id = to_upper( to_id ).
WITH
+connections AS (
SELECT spfli~carrid, carrname, connid, cityfrom, cityto
FROM spfli
INNER JOIN scarr
ON scarr~carrid = spfli~carrid
WHERE spfli~carrid BETWEEN @from_id AND @to_id ),
+sum_seats AS (
SELECT carrid, connid, SUM( seatsocc ) AS sum_seats
FROM sflight
WHERE carrid BETWEEN @from_id AND @to_id
GROUP BY carrid, connid ),
+result( name, connection, departure, arrival, occupied ) AS (
SELECT carrname, c~connid, cityfrom, cityto, sum_seats
FROM +connections AS c
INNER JOIN +sum_seats AS s
ON c~carrid = s~carrid AND
c~connid = s~connid )
SELECT *
FROM +result
ORDER BY name, connection
INTO TABLE @DATA(result).
cl_demo_output=>display( result ).