ABAP Open SQL 语法整理:SELECT、JOIN、增删改与常见坑

ABAP Open SQL 语法整理:SELECT、JOIN、增删改与常见坑
SAP 新文档中更常用的名称是 ABAP SQL,老项目和很多教材仍称 Open SQL。本文按日常 ABAP 开发的习惯整理,示例优先使用较新的
@主机变量写法。
1. Open SQL 是什么
Open SQL/ABAP SQL 是 ABAP 访问数据库的标准 SQL 层:
- 面向 ABAP Dictionary 中定义的表、视图、CDS View 等数据源。
- 尽量屏蔽底层数据库差异,但较新 ABAP SQL 功能可能与数据库平台和 ABAP 版本有关。
- 常用语句包括
SELECT、INSERT、UPDATE、MODIFY、DELETE。 - 和 Native SQL 不同,Open SQL 不直接写数据库厂商专用 SQL;需要数据库专用语法时才用
EXEC SQL ... ENDEXEC或 AMDP。
2. 现代 Open SQL 基本规则
2.1 主机变量使用 @
ABAP 变量出现在 SQL 语句里时,推荐或需要加 @:
DATA(lv_carrid) = 'LH'.
SELECT FROM sflight
FIELDS carrid, connid, fldate
WHERE carrid = @lv_carrid
INTO TABLE @DATA(lt_flights).
常见位置:
WHERE field = @lv_value
WHERE field IN @s_field
INTO @DATA(ls_row)
INTO TABLE @DATA(lt_rows)
UP TO @lv_rows ROWS
OFFSET @lv_offset
2.2 推荐显式字段列表
优先写需要的字段,少用 SELECT *:
SELECT FROM mara
FIELDS matnr, mtart, matkl
WHERE mtart = @lv_mtart
INTO TABLE @DATA(lt_mara).
2.3 表字段和别名
表别名用 AS,字段访问常用 ~:
SELECT FROM vbak AS h
INNER JOIN vbap AS i
ON i~vbeln = h~vbeln
FIELDS h~vbeln, h~erdat, i~posnr, i~matnr
WHERE h~auart = @lv_auart
INTO TABLE @DATA(lt_items).
2.4 常见执行结果字段
sy-subrc = 0:通常表示成功或读取到数据。sy-subrc = 4:通常表示未找到数据、未更新/删除任何行,或插入时存在键冲突等情况,具体看语句。sy-dbcnt:数据库语句影响或读取的行数。
SELECT SINGLE FROM mara
FIELDS matnr, mtart
WHERE matnr = @lv_matnr
INTO @DATA(ls_mara).
IF sy-subrc = 0.
" found
ENDIF.
3. SELECT 语法骨架
推荐记忆这个骨架:
SELECT [SINGLE]
FROM data_source [AS alias]
[FIELDS [DISTINCT] field_list]
[WHERE sql_condition]
[GROUP BY group_fields]
[HAVING group_condition]
[ORDER BY sort_fields]
[INTO target]
[UP TO n ROWS]
[OFFSET o].
常见现代写法:
SELECT FROM ztable AS a
FIELDS a~field1,
a~field2,
a~field3 AS alias_name
WHERE a~field1 = @lv_value
ORDER BY a~field1, a~field2
INTO TABLE @DATA(lt_result)
UP TO @lv_limit ROWS.
很多系统也常见经典写法:
SELECT field1, field2, field3
FROM ztable
WHERE field1 = @lv_value
INTO TABLE @DATA(lt_result).
4. 读取单行
4.1 按完整键读取:SELECT SINGLE
适合主键或唯一条件明确的读取:
SELECT SINGLE FROM mara
FIELDS matnr, mtart, matkl
WHERE matnr = @lv_matnr
INTO @DATA(ls_mara).
4.2 按排序取第一条:UP TO 1 ROWS
如果条件会命中多条,且你要“按某规则第一条”,用 ORDER BY ... UP TO 1 ROWS:
SELECT FROM vbak
FIELDS vbeln, erdat, ernam
WHERE kunnr = @lv_kunnr
ORDER BY erdat DESCENDING, vbeln DESCENDING
INTO TABLE @DATA(lt_latest)
UP TO 1 ROWS.
READ TABLE lt_latest INTO DATA(ls_latest) INDEX 1.
要点:
SELECT SINGLE更像“找一条已被唯一条件确定的行”。UP TO 1 ROWS更像“从多条候选中按排序取第一条”。- 没有
ORDER BY时,不要依赖数据库返回顺序。
5. 读取多行
5.1 读入内表
SELECT FROM vbap
FIELDS vbeln, posnr, matnr, kwmeng
WHERE vbeln = @lv_vbeln
INTO TABLE @DATA(lt_vbap).
5.2 追加到已有内表
SELECT FROM vbap
FIELDS vbeln, posnr, matnr
WHERE vbeln IN @s_vbeln
APPENDING TABLE @lt_vbap.
5.3 对应字段赋值
当目标结构字段名和数据库字段名相同,但字段顺序或字段数量不完全一致:
SELECT FROM mara
FIELDS matnr, mtart, matkl
WHERE mtart = @lv_mtart
INTO CORRESPONDING FIELDS OF TABLE @lt_mara.
注意:CORRESPONDING FIELDS 方便但要确认字段名匹配,避免字段没有被赋值而误以为有值。
5.4 循环读取
SELECT FROM sflight
FIELDS carrid, connid, fldate
WHERE carrid = @lv_carrid
INTO @DATA(ls_flight).
" process ls_flight
ENDSELECT.
大多数业务场景优先读入内表再处理;超大数据量、需要流式处理时再考虑 SELECT ... ENDSELECT。
5.5 分包读取
SELECT FROM zbig_table
FIELDS key1, key2, amount
WHERE bukrs = @lv_bukrs
INTO TABLE @DATA(lt_pack)
PACKAGE SIZE 1000.
" process lt_pack
ENDSELECT.
适合大批量处理,避免一次性把所有数据放入内存。
6. WHERE 条件
6.1 常用条件
WHERE field = @lv_value
WHERE field <> @lv_value
WHERE field BETWEEN @lv_low AND @lv_high
WHERE field IN @s_field
WHERE field LIKE @lv_pattern
WHERE field IS NULL
WHERE field IS NOT NULL
WHERE field IS INITIAL
WHERE field IS NOT INITIAL
组合条件:
WHERE bukrs = @lv_bukrs
AND gjahr = @lv_gjahr
AND ( blart = 'SA' OR blart = 'KR' )
6.2 IN @range
选择屏幕的 SELECT-OPTIONS 可以直接用于 IN:
SELECT-OPTIONS s_matnr FOR mara-matnr.
SELECT FROM mara
FIELDS matnr, mtart
WHERE matnr IN @s_matnr
INTO TABLE @DATA(lt_mara).
6.3 LIKE
DATA(lv_pattern) = 'ABC%'.
SELECT FROM mara
FIELDS matnr, maktx
WHERE matnr LIKE @lv_pattern
INTO TABLE @DATA(lt_result).
常见通配符:
%:任意长度字符。_:单个字符。
6.4 初始值和空值
ABAP 初始值和数据库 NULL 不是一回事:
WHERE field IS INITIAL
WHERE field IS NULL
常规 SAP 透明表字段通常不是 NULL,但外连接、CDS、SQL 表达式等场景可能产生空值。
7. JOIN
7.1 INNER JOIN
只返回两边都匹配的行:
SELECT FROM vbak AS h
INNER JOIN vbap AS i
ON i~vbeln = h~vbeln
FIELDS h~vbeln,
h~auart,
i~posnr,
i~matnr
WHERE h~vkorg = @lv_vkorg
INTO TABLE @DATA(lt_so_items).
7.2 LEFT OUTER JOIN
保留左表行,右表没有匹配时右表字段为空值或初始值:
SELECT FROM vbak AS h
LEFT OUTER JOIN vbap AS i
ON i~vbeln = h~vbeln
FIELDS h~vbeln,
h~auart,
i~posnr,
i~matnr
WHERE h~vkorg = @lv_vkorg
INTO TABLE @DATA(lt_result).
注意:如果把右表字段条件写在 WHERE 里,可能让外连接效果接近内连接。右表筛选条件很多时候应放在 ON 里:
SELECT FROM vbak AS h
LEFT OUTER JOIN vbap AS i
ON i~vbeln = h~vbeln
AND i~matnr = @lv_matnr
FIELDS h~vbeln, i~posnr, i~matnr
INTO TABLE @DATA(lt_result).
8. 子查询
8.1 EXISTS
SELECT FROM vbak AS h
FIELDS h~vbeln, h~kunnr
WHERE EXISTS (
SELECT FROM vbap AS i
FIELDS i~vbeln
WHERE i~vbeln = h~vbeln
AND i~matnr = @lv_matnr
)
INTO TABLE @DATA(lt_orders).
8.2 IN ( SELECT ... )
SELECT FROM mara
FIELDS matnr, mtart
WHERE matnr IN (
SELECT FROM marc
FIELDS matnr
WHERE werks = @lv_werks
)
INTO TABLE @DATA(lt_mara).
9. FOR ALL ENTRIES
FOR ALL ENTRIES 常用于“用内表中的键去数据库取明细”:
IF lt_keys IS NOT INITIAL.
SELECT FROM vbap
FIELDS vbeln, posnr, matnr
FOR ALL ENTRIES IN @lt_keys
WHERE vbeln = @lt_keys-vbeln
INTO TABLE @DATA(lt_vbap).
ENDIF.
必须注意:
lt_keys为空时不要执行,否则可能读取全表。- 先删除驱动内表重复键,减少数据库负担。
- 条件尽量覆盖足够字段,避免取回过多数据。
- 新系统可以优先考虑
JOIN、IN @range、或内表作为数据源。
去重示例:
SORT lt_keys BY vbeln.
DELETE ADJACENT DUPLICATES FROM lt_keys COMPARING vbeln.
10. 内表作为数据源
较新 ABAP 版本支持在 SELECT 中把内表作为数据源,适合替代部分 FOR ALL ENTRIES:
SELECT FROM @lt_keys AS k
INNER JOIN vbap AS i
ON i~vbeln = k~vbeln
FIELDS i~vbeln, i~posnr, i~matnr
INTO TABLE @DATA(lt_vbap).
注意:该能力依赖系统版本;大内表可能被传到数据库侧,应结合数据量和执行计划评估。
11. 聚合与分组
11.1 常用聚合函数
SELECT FROM vbap
FIELDS vbeln,
COUNT( * ) AS item_count,
SUM( kwmeng ) AS total_qty,
MIN( posnr ) AS first_posnr,
MAX( posnr ) AS last_posnr
WHERE vbeln IN @s_vbeln
GROUP BY vbeln
INTO TABLE @DATA(lt_summary).
常用聚合:
COUNT( * )COUNT( DISTINCT field )SUM( field )AVG( field )MIN( field )MAX( field )
11.2 HAVING
WHERE 过滤明细行,HAVING 过滤分组后的结果:
SELECT FROM vbap
FIELDS vbeln, SUM( kwmeng ) AS total_qty
GROUP BY vbeln
HAVING SUM( kwmeng ) > @lv_min_qty
INTO TABLE @DATA(lt_result).
12. 排序与分页
12.1 ORDER BY
SELECT FROM vbak
FIELDS vbeln, erdat, ernam
WHERE erdat BETWEEN @lv_from AND @lv_to
ORDER BY erdat DESCENDING, vbeln ASCENDING
INTO TABLE @DATA(lt_orders).
常见写法:
ORDER BY PRIMARY KEY
ORDER BY field1 ASCENDING, field2 DESCENDING
要点:
- 不写
ORDER BY就不要假设返回顺序。 - 分页、取最新、取最早等场景必须显式排序。
12.2 UP TO n ROWS
SELECT FROM mara
FIELDS matnr, mtart
WHERE mtart = @lv_mtart
INTO TABLE @DATA(lt_mara)
UP TO 100 ROWS.
12.3 OFFSET
SELECT FROM ztable
FIELDS key1, text1
WHERE status = @lv_status
ORDER BY key1
INTO TABLE @DATA(lt_page)
UP TO @lv_page_size ROWS
OFFSET @lv_offset.
要点:
- 使用
OFFSET时需要稳定排序。 ORDER BY字段最好能唯一确定顺序,否则分页可能跳行或重复。
13. SQL 表达式
13.1 字段别名
SELECT FROM mara
FIELDS matnr AS material,
mtart AS material_type
INTO TABLE @DATA(lt_result).
13.2 CASE
SELECT FROM vbak
FIELDS vbeln,
CASE auart
WHEN 'OR' THEN 'Standard Order'
WHEN 'RE' THEN 'Return'
ELSE 'Other'
END AS order_type_text
INTO TABLE @DATA(lt_orders).
13.3 COALESCE
SELECT FROM ztable
FIELDS key1,
coalesce( optional_text, fallback_text ) AS display_text
INTO TABLE @DATA(lt_result).
13.4 CAST
SELECT FROM ztable
FIELDS key1,
CAST( amount AS DEC( 15, 2 ) ) AS amount_dec
INTO TABLE @DATA(lt_result).
13.5 算术表达式
SELECT FROM vbap
FIELDS vbeln,
posnr,
kwmeng * netpr AS gross_value
INTO TABLE @DATA(lt_result).
14. DISTINCT
SELECT FROM vbap
FIELDS DISTINCT matnr
WHERE werks = @lv_werks
INTO TABLE @DATA(lt_matnr).
适合去重,但不要把它当成修复重复数据逻辑的万能手段。能从业务键上明确唯一性时,优先明确业务键。
15. CTE:WITH
Common Table Expression 适合把复杂查询拆成可读的临时结果:
WITH
+orders AS (
SELECT FROM vbak
FIELDS vbeln, kunnr, erdat
WHERE erdat >= @lv_from_date
),
+items AS (
SELECT FROM vbap
FIELDS vbeln, posnr, matnr
)
SELECT FROM +orders AS h
INNER JOIN +items AS i
ON i~vbeln = h~vbeln
FIELDS h~vbeln, h~kunnr, i~posnr, i~matnr
INTO TABLE @DATA(lt_result).
CTE 名称通常以 + 开头。
16. 集合操作
较新 ABAP SQL 支持集合操作,具体以系统版本为准:
SELECT FROM ztable_a
FIELDS key1, text1
WHERE status = 'A'
UNION ALL
SELECT FROM ztable_b
FIELDS key1, text1
WHERE status = 'A'
INTO TABLE @DATA(lt_union).
常见集合操作:
UNION:合并并去重。UNION ALL:合并但保留重复。INTERSECT:交集。EXCEPT:差集。
17. 动态 Open SQL
17.1 动态表名
DATA(lv_tabname) = 'MARA'.
SELECT FROM (lv_tabname)
FIELDS *
INTO TABLE @DATA(lt_data)
UP TO 10 ROWS.
17.2 动态字段
DATA lt_fields TYPE STANDARD TABLE OF string WITH EMPTY KEY.
lt_fields = VALUE #( ( `MATNR` ) ( `MTART` ) ).
TYPES: BEGIN OF ty_mara_sel,
matnr TYPE mara-matnr,
mtart TYPE mara-mtart,
END OF ty_mara_sel.
DATA lt_result TYPE STANDARD TABLE OF ty_mara_sel WITH EMPTY KEY.
SELECT (lt_fields)
FROM mara
INTO TABLE @lt_result
UP TO 10 ROWS.
17.3 动态条件
DATA(lv_where) = `MTART = 'FERT'`.
SELECT FROM mara
FIELDS matnr, mtart
WHERE (lv_where)
INTO TABLE @DATA(lt_mara).
注意:
- 动态 SQL 要做白名单校验。
- 不要直接拼接未校验的用户输入。
- 能用静态 SQL 和
@主机变量时,优先用静态写法。
18. INSERT
18.1 插入单行
DATA ls_ztab TYPE ztable.
ls_ztab-key1 = lv_key1.
ls_ztab-text1 = lv_text.
INSERT ztable FROM @ls_ztab.
IF sy-subrc = 0.
" inserted
ENDIF.
18.2 插入多行
INSERT ztable FROM TABLE @lt_ztab.
DATA(lv_inserted) = sy-dbcnt.
18.3 接受重复键
INSERT ztable FROM TABLE @lt_ztab ACCEPTING DUPLICATE KEYS.
DATA(lv_inserted) = sy-dbcnt.
适合批量插入时跳过已存在记录,但需要用 sy-dbcnt 判断实际插入数量。
19. UPDATE
19.1 按条件更新
UPDATE ztable
SET status = @lv_status,
changed_by = @sy-uname,
changed_on = @sy-datum
WHERE key1 = @lv_key1.
DATA(lv_updated) = sy-dbcnt.
19.2 按工作区更新
UPDATE ztable FROM @ls_ztab.
按工作区更新时,数据库行通常由主键字段定位;要确认工作区中的键字段完整且正确。
19.3 批量更新
UPDATE ztable FROM TABLE @lt_ztab.
DATA(lv_updated) = sy-dbcnt.
20. MODIFY
MODIFY dbtab 对数据库表是“按主键存在则更新,不存在则插入”的 upsert 式操作:
MODIFY ztable FROM @ls_ztab.
MODIFY ztable FROM TABLE @lt_ztab.
注意:
- 需要明确区分“新增”和“修改”时,不要无脑使用
MODIFY。 - 如果业务要求重复时报错,应使用
INSERT并检查结果。 - 如果业务要求不存在时报错,应使用
UPDATE并检查sy-dbcnt。
21. DELETE
21.1 按条件删除
DELETE FROM ztable
WHERE key1 = @lv_key1
AND status = @lv_status.
DATA(lv_deleted) = sy-dbcnt.
21.2 按工作区删除
DELETE ztable FROM @ls_ztab.
21.3 批量删除
DELETE ztable FROM TABLE @lt_ztab.
DATA(lv_deleted) = sy-dbcnt.
注意:DELETE FROM ztable. 没有 WHERE 会删除整张表数据,开发和生产都要极其谨慎。
22. 事务、提交与回滚
Open SQL 写操作属于 SAP LUW:
INSERT ztable FROM TABLE @lt_data.
IF sy-subrc = 0.
COMMIT WORK.
ELSE.
ROLLBACK WORK.
ENDIF.
实践建议:
- 报表或自定义批处理可以在明确边界处
COMMIT WORK。 - BAdI、User Exit、增强点、更新任务等框架内,通常不要随意提交,由外层业务流程控制事务。
- 多表更新要设计一致性:任一关键步骤失败时应回滚或补偿。
23. 锁
Open SQL 的 UPDATE/DELETE 不等于 SAP 业务锁。需要业务并发控制时,优先使用锁对象:
CALL FUNCTION 'ENQUEUE_EZ_MY_LOCK'
EXPORTING
key1 = lv_key1.
" Open SQL update/delete
CALL FUNCTION 'DEQUEUE_EZ_MY_LOCK'
EXPORTING
key1 = lv_key1.
实践建议:
- 修改业务主数据、凭证、配置表前先确认是否已有标准锁对象。
- 不要只靠“先 SELECT 再 UPDATE”来防并发覆盖。
- 需要防止覆盖时,可在
WHERE中加入版本号、时间戳或旧值条件。
24. 常用业务模板
24.1 判断是否存在
SELECT FROM ztable
FIELDS key1
WHERE key1 = @lv_key1
INTO @DATA(lv_dummy)
UP TO 1 ROWS.
ENDSELECT.
IF sy-subrc = 0.
" exists
ENDIF.
如果是完整主键,也可以:
SELECT SINGLE FROM ztable
FIELDS key1
WHERE key1 = @lv_key1
INTO @DATA(lv_key_found).
24.2 查主表和明细
SELECT FROM vbak AS h
INNER JOIN vbap AS i
ON i~vbeln = h~vbeln
FIELDS h~vbeln,
h~kunnr,
h~erdat,
i~posnr,
i~matnr,
i~kwmeng
WHERE h~vbeln IN @s_vbeln
INTO TABLE @DATA(lt_sales).
24.3 批量按键查描述
SORT lt_matnr BY matnr.
DELETE ADJACENT DUPLICATES FROM lt_matnr COMPARING matnr.
IF lt_matnr IS NOT INITIAL.
SELECT FROM makt
FIELDS matnr, maktx
FOR ALL ENTRIES IN @lt_matnr
WHERE matnr = @lt_matnr-matnr
AND spras = @sy-langu
INTO TABLE @DATA(lt_makt).
ENDIF.
24.4 批量更新状态
UPDATE ztable
SET status = @gc_status_done,
changed_by = @sy-uname,
changed_on = @sy-datum
WHERE run_id = @lv_run_id
AND status = @gc_status_open.
DATA(lv_updated) = sy-dbcnt.
24.5 安全 upsert
SELECT SINGLE FROM ztable
FIELDS key1
WHERE key1 = @ls_data-key1
INTO @DATA(lv_existing_key).
IF sy-subrc = 0.
UPDATE ztable FROM @ls_data.
ELSE.
INSERT ztable FROM @ls_data.
ENDIF.
如果并发要求高,需要配合锁对象或唯一键异常处理。
25. 性能与可维护性检查清单
- 尽量不要
SELECT *,只取需要字段。 - 不要依赖数据库默认排序,需要顺序就写
ORDER BY。 - 避免在
LOOP中反复SELECT SINGLE;先收集键,再一次性查询。 FOR ALL ENTRIES前必须判断内表非空,并尽量去重。- 条件尽量使用索引字段或主键字段。
- 大批量处理用
PACKAGE SIZE或按键分页。 - 聚合、过滤、排序尽量让数据库完成,不要全量取回 ABAP 再处理。
- 写操作后检查
sy-subrc和sy-dbcnt。 - 多表写入要考虑事务边界、锁和失败回滚。
- 动态 SQL 必须做白名单校验。
- 外连接右表条件的位置要谨慎,确认写在
ON还是WHERE。 - 分页使用稳定且尽量唯一的排序字段。
26. 新旧写法对照
26.1 旧式工作区
DATA: ls_mara TYPE mara,
lt_mara TYPE TABLE OF mara.
SELECT matnr mtart matkl
FROM mara
INTO CORRESPONDING FIELDS OF TABLE lt_mara
WHERE mtart = lv_mtart.
26.2 现代写法
SELECT FROM mara
FIELDS matnr, mtart, matkl
WHERE mtart = @lv_mtart
INTO TABLE @DATA(lt_mara).
26.3 旧式变量混写
SELECT SINGLE matnr mtart
FROM mara
INTO ls_mara
WHERE matnr = lv_matnr.
26.4 现代写法
SELECT SINGLE FROM mara
FIELDS matnr, mtart
WHERE matnr = @lv_matnr
INTO @DATA(ls_mara).
27. 常见坑
27.1 FOR ALL ENTRIES 驱动表为空
错误风险:
SELECT FROM vbap
FIELDS vbeln, posnr
FOR ALL ENTRIES IN @lt_keys
WHERE vbeln = @lt_keys-vbeln
INTO TABLE @DATA(lt_vbap).
正确习惯:
IF lt_keys IS NOT INITIAL.
SELECT FROM vbap
FIELDS vbeln, posnr
FOR ALL ENTRIES IN @lt_keys
WHERE vbeln = @lt_keys-vbeln
INTO TABLE @DATA(lt_vbap).
ENDIF.
27.2 UP TO 1 ROWS 没有排序
SELECT FROM vbak
FIELDS vbeln, erdat
WHERE kunnr = @lv_kunnr
INTO TABLE @DATA(lt_one)
UP TO 1 ROWS.
这不是“最新一条”,只是不确定的一条。要写:
SELECT FROM vbak
FIELDS vbeln, erdat
WHERE kunnr = @lv_kunnr
ORDER BY erdat DESCENDING, vbeln DESCENDING
INTO TABLE @DATA(lt_one)
UP TO 1 ROWS.
27.3 LEFT JOIN 右表条件写错位置
可能破坏外连接语义:
SELECT FROM zhead AS h
LEFT OUTER JOIN zitem AS i
ON i~docno = h~docno
FIELDS h~docno, i~itemno
WHERE i~status = 'A'
INTO TABLE @DATA(lt_result).
通常应考虑:
SELECT FROM zhead AS h
LEFT OUTER JOIN zitem AS i
ON i~docno = h~docno
AND i~status = 'A'
FIELDS h~docno, i~itemno
INTO TABLE @DATA(lt_result).
27.4 MODIFY 掩盖业务语义
MODIFY 很方便,但它会模糊“应该新增”还是“应该修改”。接口、财务、库存等关键逻辑中,建议明确使用 INSERT 或 UPDATE 并检查结果。
28. 官方参考
- SAP ABAP Keyword Documentation: ABAP SQL Overview
https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/ABENABAP_SQL_OVIEW.html - SAP ABAP Keyword Documentation: SELECT
https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/ABAPSELECT.html - SAP ABAP Keyword Documentation: Host Variables
https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/ABENABAP_SQL_HOST_VARIABLES.html - SAP ABAP Keyword Documentation: UP TO / OFFSET
https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/ABAPSELECT_UP_TO_OFFSET.html
