graph TD
A[CDS注解] --> B[ABAP目录注解]
A --> C[访问控制注解]
A --> D[文本注解]
A --> E[语义注解]
A --> F[对象模型注解]
A --> G[聚合注解]
A --> H[消费注解]
A --> I[VDM/OData注解]
A --> J[分析注解]
A --> K[系统字段注解]
@AbapCatalog.sqlViewName: 'ZMY_CDS_VIEW' @AccessControl.authorizationCheck: #NOT_REQUIRED define view ZMY_CDS as select from mara { key matnr, mtart, maktx, @Semantics.unitOfMeasure: 'EA' meins }
使用CASE条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@AbapCatalog.sqlViewName: 'ZMATERIAL_STATUS' @AccessControl.authorizationCheck: #NOT_REQUIRED define view ZMATERIAL_STATUS as select from mara { key matnr, mtart, maktx, case when mtart = 'FERT' then 'Finished Goods' when mtart = 'HALB' then 'Semi-finished' when mtart = 'ROH' then 'Raw Material' else 'Other' end as MaterialStatus }
使用WHERE条件
1 2 3 4 5 6 7 8 9 10 11
@AbapCatalog.sqlViewName: 'ZMATERIAL_ACTIVE' @AccessControl.authorizationCheck: #NOT_REQUIRED define view ZMATERIAL_ACTIVE as select from mara { key matnr, mtart, maktx, meins } where matnr in ('1000', '1001', '1002')
使用CAST语句
1 2 3 4 5 6 7 8 9 10 11
@AbapCatalog.sqlViewName: 'ZMATERIAL_PRICE' @AccessControl.authorizationCheck: #NOT_REQUIRED define view ZMATERIAL_PRICE as select from mara as Material join mbew as Price on Material.matnr = Price.matnr { key Material.matnr, Material.maktx, cast( Price.price as abap.dec(15,2) ) as MaterialPrice, cast( Price.currency as abap.cuky ) as Currency }
使用Association
1 2 3 4 5 6 7 8 9 10 11 12
@AbapCatalog.sqlViewName: 'ZMATERIAL_SUPPLIER' @AccessControl.authorizationCheck: #NOT_REQUIRED define view ZMATERIAL_SUPPLIER as select from mara as Material association [1] to EKPO as PurchaseOrder on $projection.matnr = PurchaseOrder.matnr { key Material.matnr, Material.maktx, PurchaseOrder.ebeln, PurchaseOrder.ebelp }
定义选择参数
1 2 3 4 5 6 7 8 9 10 11
@AbapCatalog.sqlViewName: 'ZMATERIAL_SEL' @AccessControl.authorizationCheck: #NOT_REQUIRED define view ZMATERIAL_SEL as select from mara { key matnr, mtart, maktx, meins } parameters p_matnr : matnr
graph LR
A["1. 安装Eclipse<br>+ ADT"] --> B["2. 创建ABAP<br>项目"]
B --> C["3. 创建CDS<br>Data Definition"]
C --> D["4. 定义CDS<br>视图"]
D --> E["5. 检查并<br>激活"]
E --> F["6. 添加oData<br>注解"]
F --> G["7. 激活服务<br>+ 测试"]
⚠️ 注意事项
CDS视图激活后==不能修改==,只能删除重新创建
sqlViewName 和 define view 后面的名称==不能相同==
选择屏幕目前只支持==单值==(parameters)
S/4系统的某些表需要使用对应的==CDS视图==才能查询到数据
URI需要==区分大小写==
在ABAP程序中调用时使用的是 sqlViewName
ABAP程序调用CDS视图
1 2 3 4 5 6 7 8 9 10 11 12 13
REPORT z_cds_call_example.
SELECT * FROM ZMATERIAL_COMPLETE INTO TABLE @DATA(lt_material) WHERE matnr = '1000'.
graph TD
A[开始DO循环] --> B{次数限制?}
B -->|有n次| C{计数器 <= n?}
B -->|无限制| D{循环继续}
C -->|是| E[执行语句块]
C -->|否| F[结束循环]
D --> G[执行语句块]
E --> H{是否继续?}
G --> H
H -->|是| D
H -->|否| F
F --> I[继续执行]
📝 基本示例
固定次数循环
1 2 3 4
REPORT YH_SEP_15. DO 15 TIMES. WRITE: / 'Hello'. ENDDO.
* 定义工作区 DATA: BEGIN OF wa, connid TYPE spfli-connid, cityfrom TYPE spfli-cityfrom, cityto TYPE spfli-cityto, END OF wa.
* 定义变量 DATA c1 TYPE spfli-carrid VALUE 'LH'.
* 执行Native SQL EXEC SQL PERFORMING loop_output. SELECT connid, cityfrom, cityto INTO :wa FROM SPFLI WHERE carrid = :c1 ENDEXEC.
* 处理子程序 FORM loop_output. WRITE: / wa-connid, wa-cityfrom, wa-cityto. ENDFORM.
输出示例
1 2 3
0400 FRANKFURT NEW YORK 2402 FRANKFURT BERLIN 0402 FRANKFURT NEW YORK
🔍 Native SQL的使用场景
1. 数据定义语言(DDL)
1 2 3 4 5 6 7
EXEC SQL. CREATE TABLE TEMP_TABLE ( ID NUMBER(10), NAME VARCHAR2(100), CREATED_DATE DATE ) ENDEXEC.
2. 复杂查询
1 2 3 4 5 6 7 8
EXEC SQL. SELECT a.*, b.name INTO :wa_a, :wa_b FROM table1 a JOIN table2 b ON a.id = b.id WHERE a.status = :status ORDER BY a.created_date DESC ENDEXEC.
3. 批量操作
1 2 3 4 5 6 7 8 9 10 11 12
* 使用PERFORMING处理多行结果 EXEC SQL PERFORMING process_rows. SELECT id, name, email INTO :wa_id, :wa_name, :wa_email FROM customers WHERE active = 1 ENDEXEC.
FORM process_rows. " 处理每一行数据 WRITE: / wa_id, wa_name, wa_email. ENDFORM.
🎯 Native SQL vs Open SQL
特性
Native SQL
Open SQL
语法
数据库特定
ABAP标准
表访问
任何数据库表
ABAP字典表
DDL支持
完全支持
不支持
转换
无转换
自动转换
性能
高(直接)
中等(通过接口)
维护性
低(依赖数据库)
高(独立)
⚠️ Native SQL注意事项
1. 数据库依赖性
语法因数据库而异
需要了解特定数据库的SQL方言
移植性差
2. 性能考虑
直接访问数据库,性能更高
但失去了ABAP的优化层
需要手动管理事务
3. 安全风险
可能存在SQL注入风险
需要谨慎处理用户输入
建议使用参数化查询
🔧 最佳实践
1. 参数化查询
1 2 3 4 5 6 7 8 9 10 11 12
* 安全的参数化查询 DATA: lv_carrid TYPE spfli-carrid, wa_spfli TYPE spfli.
lv_carrid = 'LH'.
EXEC SQL. SELECT * INTO :wa_spfli FROM spfli WHERE carrid = :lv_carrid ENDEXEC.
2. 错误处理
1 2 3 4 5 6 7 8 9 10 11
* 添加错误处理 DATA: lv_rc TYPE i.
EXEC SQL. INSERT INTO temp_table (id, name) VALUES (1, 'Test') INTO :wa_spfli ENDEXEC.
IF sy-subrc <> 0. WRITE: / 'SQL执行错误:', sy-subrc. ENDIF.
graph TD
A[循环控制语句] --> B["EXIT<br>退出整个循环"]
A --> C["CHECK<br>条件跳过迭代"]
A --> D["CONTINUE<br>跳到下次迭代"]
B --> B1["循环 i = 1,2,3<br>EXIT at i=2<br>输出: 1"]
C --> C1["循环 i = 1,2,3<br>CHECK i<>2<br>输出: 1, 3"]
D --> D1["循环 i = 1,2,3<br>CONTINUE at i=2<br>输出: 1, 3"]
🏗️ 最佳实践
1. 明确的退出条件
1 2 3 4 5 6 7 8
" ✅ 好的做法 - 条件明确 LOOP AT lt_items INTO ls_item. IF ls_item-status = 'COMPLETED' AND lv_all_processed = abap_true. EXIT. ENDIF. " 处理逻辑 PERFORM process_item USING ls_item. ENDLOOP.
2. 达到限制后退出
1 2 3 4 5 6 7 8 9
LOOP AT lt_items INTO ls_item. " 达到最大处理数量后退出 IF lv_processed_count >= gv_max_items. EXIT. ENDIF.
" 准备内表数据 APPEND VALUE #( name = '张三' age = 30 email = 'zhangsan@example.com' ) TO lt_person. APPEND VALUE #( name = '李四' age = 28 email = 'lisi@example.com' ) TO lt_person.
DO [n TIMES]. <statement block n>. DO [m TIMES]. <statement block m>. ENDDO. ENDDO.
嵌套WHILE循环语法
1 2 3 4 5 6
WHILE <condition1>. <statement block 1>. WHILE <condition2>. <statement block 2>. ENDWHILE. ENDWHILE.
混合嵌套语法
1 2 3 4 5 6
DO [n TIMES]. <statement block 1>. WHILE <condition>. <statement block 2>. ENDWHILE. ENDDO.
📊 嵌套循环执行流程
graph TD
A[开始外层循环] --> B{外层条件}
B -->|满足| C[执行外层语句块]
B -->|不满足| G[结束外层循环]
C --> D{进入内层循环}
D --> E{内层条件}
E -->|满足| F[执行内层语句块]
E -->|不满足| H[退出内层循环]
F --> I{继续内层循环?}
I -->|是| E
I -->|否| C
H --> C
G --> J[继续执行]
📝 示例代码
1. 简单嵌套DO循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
REPORT ys_sep_15. DATA: a1 TYPE i, b1 TYPE i. a1 = 0. b1 = 0.
" 处理二维数据 DATA: lt_matrix TYPE TABLE OF TABLE OF i, lv_row TYPE I, lv_col TYPE I.
" 填充矩阵 DO 5 TIMES. DATA: lt_row TYPE TABLE OF i. DO 5 TIMES. APPEND sy-index TO lt_row. ENDDO. APPEND lt_row TO lt_matrix. ENDDO.
" 读取矩阵 LOOP AT lt_matrix INTO DATA(lt_row). DO 5 TIMES. lv_col = sy-index. WRITE: / lt_row[ lv_col ]. ENDDO. ENDLOOP.
2. 多层条件检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
" 检查多层数据 SELECT * FROM vbak INTO TABLE @DATA(lt_vbak) WHERE vkorg = '1000'.
LOOP AT lt_vbak INTO DATA(lwa_vbak). DO 3 TIMES. " 检查3个订单项 SELECT * FROM vbap INTO TABLE @DATA(lt_vap) WHERE vbeln = lwa_vbak-vbeln AND posnr = sy-index. IF sy-subrc = 0. LOOP AT lt_vap INTO DATA(lwa_vap). WRITE: / 'Order:', lwa_vbak-vbeln, 'Item:', lwa_vap-posnr, 'Material:', lwa_vap-matnr. ENDLOOP. ENDIF. ENDDO. ENDLOOP.
graph LR
A[BADI优势] --> B[灵活性]
A --> C[上下文支持]
A --> D[过滤器功能]
A --> E[多客户支持]
A --> F[可重复使用]
B --> B1["GET BADI / CALL BADI"]
C --> C1["上下文相关的增强"]
D --> D1["基于过滤数据的增强"]
E --> E1["多客户同时使用"]
F --> F1["可以多次实现"]