SAP Native SQL 简介及实现方式(EXEC SQL、ADBC、AMDP)
- 1、SAP Open SQL 与 Native SQL 的特点
- 2、Native SQL 的实现方式
- 方式一:Exec SQL
- (1)获取单值
- (2)获取多行
- (3)游标应用
- (4)错误捕获
- (5)访问DBCO中配置的数据库链接
- (6)执行DDL语句
- (7)调用存储过程
- (8)调用自定义函数
- 方式二:ADBC
- (9)ADBC示例
- 方式三:AMDP
- (10)编写SAP库存查询功能
1、SAP Open SQL 与 Native SQL 的特点
在 ABAP/4 编程语言中,提供了两种类型的 SQL。
第一种:Open SQL
(1)SAP 为 ABAP 定义的数据库无关的 SQL 标准, 为 SAP 支持的所有数据库系统提供了统一的语法和语义。
(2)ABAP中的Database Interface层负责将Open SQL在运行时由系统动态的转化成对应数据库使用的本地SQL。
(3)ABAPer在编写程序时不需要考虑 SAP 系统使用的数据库差异,操作的结果和任何错误消息都与正在使用的数据库系统无关。
(4)基于Open SQL开发的ABAP程序,可以在SAP系统中复用,而不用关心底层数据库的类型。
(5)Open SQL 语句只能访问在 ABAP 字典中创建的数据库表、视图,而不能操作那些直接通过数据库工具创建的表。
(6)Open SQL具有一些功能限制,即只有标准SQL的DML有对应的Open SQL,如:SELECT、INSERT, UPDATE, DELETE。
第二种:Native SQL
(1)每种关系型数据库都有其对应的 SQL,是数据库相关的。
(2)Native SQL绕过ABAP中的Database Interface层,不加转换的直接访问数据库层的Database Interface层。
(3)不同的 SAP 系统可能使用各种不同的数据库,使用Native SQL 的 ABAP 程序无法适应所有的 SAP 系统。
(4)Native SQL 通过设定的数据库链接,可以访问特定的数据库,可以访问不受 ABAP 字典管理的数据库对象,如表、视图、存储过程,以及外部的第三方数据库系统。
(5)Native SQL不会用到缓存,会直接发送给数据库,而不会经过ABAP数据访问层。除开DML,它一般用于DDL、DCL,可以用来维护数据库对象。
(6)可直接对数据库表进行修改删除等操作,有一定安全风险 。
说明及注意事项:
① SAP升级到S4之后,只支持SAP HANA数据库。理论上HANA数据库是向下兼容的,所以基于Hana的Native SQL的ABAP程序也具备复用性。
② Native SQL不会像Open SQL会默认过滤当前客户端号,所有语句都需要自己指定。
③ 本文仅做学习研究用,在SAP日常开发中,建议非必要不使用NativeSQL。
2、Native SQL 的实现方式
方式一:Exec SQL
语法:
EXEC SQL [PERFORMING <form_routine>].
<native_sql_statements>
ENDEXEC.
SE11查看测试表SCARR的数据:
(1)获取单值
REPORT yz_demo1.
DATA: lv_count TYPE i.
EXEC SQL.
select count(1) into :lv_count
from saphanadb.scarr
where mandt = :sy-MANDT ;
ENDEXEC.
WRITE:/ lv_count.
(2)获取多行
REPORT yz_demo2.
DATA: lv_carrid TYPE scarr-carrid,
lv_carrname TYPE scarr-carrname.
EXEC SQL PERFORMING Write_data.
select carrid, carrname into :lv_carrid,:lv_carrname
from saphanadb.scarr
where mandt = :sy-MANDT ;
ENDEXEC.
FORM Write_data.
WRITE:/ lv_carrid,'',lv_carrname.
ENDFORM.
(3)游标应用
REPORT yz_demo3.
DATA: BEGIN OF gs_scarr,
carrid TYPE scarr-carrid,
carrname TYPE scarr-carrname,
END OF gs_scarr.
EXEC SQL.
OPEN cursor FOR
select carrid, carrname
from saphanadb.scarr
where mandt = :sy-MANDT
ENDEXEC.
DO.
CLEAR gs_scarr.
EXEC SQL.
FETCH NEXT cursor INTO :gs_scarr
ENDEXEC.
IF sy-subrc <> 0.
EXIT.
ELSE.
WRITE:/ gs_scarr-carrid,'',gs_scarr-carrname.
ENDIF.
ENDDO.
EXEC SQL.
CLOSE cursor
ENDEXEC.
(4)错误捕获
REPORT yz_demo4.
DATA lv_store_dbs TYPE dbcon-con_name.
DATA: lv_exc_ref TYPE REF TO cx_sy_native_sql_error,
lv_error_text TYPE string.
TRY.
EXEC SQL.
CONNECT TO :lv_store_dbs
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
CATCH cx_sy_native_sql_error INTO lv_exc_ref.
CLEAR: lv_error_text.
lv_error_text = lv_exc_ref->get_text( ).
MESSAGE lv_error_text TYPE 'I'.
ENDTRY.
(5)访问DBCO中配置的数据库链接
REPORT yz_demo5.
DATA conn TYPE dbcon-con_name.
cl_demo_input=>request( CHANGING field = conn ).
*SELECT SINGLE dbms
*FROM dbcon
*WHERE con_name = @conn AND dbms = 'HDB'
*INTO @DATA(dbtype).
*
*IF sy-subrc <> 0.
* RETURN.
*ENDIF.
TRY.
EXEC SQL.
CONNECT TO :conn
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error
EXPORTING
textid = cx_sy_native_sql_error=>cx_sy_native_sql_error.
ENDIF.
EXEC SQL.
OPEN dbcur FOR
SELECT carrid
FROM scarr
WHERE mandt = :sy-mandt
ENDEXEC.
DATA carrid TYPE scarr-carrid.
DO.
EXEC SQL.
FETCH NEXT dbcur INTO :carrid
ENDEXEC.
IF sy-subrc <> 0.
EXIT.
ELSE.
cl_demo_output=>write( |{ carrid }| ).
ENDIF.
ENDDO.
EXEC SQL.
CLOSE dbcur
ENDEXEC.
EXEC SQL.
DISCONNECT :conn
ENDEXEC.
CATCH cx_sy_native_sql_error INTO DATA(exc).
cl_demo_output=>write( exc->get_text( ) ).
ENDTRY.
cl_demo_output=>display( ).
(6)执行DDL语句
REPORT yz_demo6.
DATA: lv_count TYPE i.
DATA: lv_exc_ref TYPE REF TO cx_sy_native_sql_error,
lv_error_text TYPE string.
TRY.
EXEC SQL.
drop table ZStudent;
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
EXEC SQL.
create table ZStudent
(
ZNo int,
ZName nvarchar(10),
ZSex nvarchar(1),
ZAge int,
primary key (ZNo)
);
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
EXEC SQL.
insert into ZStudent
values( 1, '张三', '男', 18 );
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
EXEC SQL.
insert into saphanadb.ZStudent
values( 2, '李四', '女', 19 );
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
EXEC SQL.
update ZStudent
set zsex = '男', zage = 18
where zname = '李四';
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
EXEC SQL.
select count(1) into :lv_count
from ZStudent
where zage = 18;
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
EXEC SQL.
commit;
ENDEXEC.
CATCH cx_sy_native_sql_error INTO lv_exc_ref.
CLEAR: lv_error_text.
lv_error_text = lv_exc_ref->get_text( ).
MESSAGE lv_error_text TYPE 'I'.
EXEC SQL.
rollback;
ENDEXEC.
ENDTRY.
WRITE:/ '18岁的同学共有', lv_count, '位。' .
(7)调用存储过程
第1步:一般我们没有SAPHANADB的修改权限,也不建议在其中新建任何自定义对象,所以在SAPHANADB对应租户中新建用户NewUser,在新建用户名对应Schema下,定义如下存储过程:
create or replace procedure newuser.zp_scarr4
(
IN I_CLIENT int default 300, -- 传入参数:客户端号
OUT O_CARRID varchar(10), -- 传出参数:航空公司ID
OUT O_CARRNAME varchar(50) -- 传出参数:航空公司名称
)
as
begin
select top 1 CARRID, CARRNAME
--注意事项:使用select into给参数或内部变量赋值,不需要 “:”
into O_CARRID, O_CARRNAME
from saphanadb.scarr
where mandt = :I_CLIENT;
end;
--在Hana studio中执行存储过程
call newuser.zp_scarr4(200,?,?);
--或者
call newuser.zp_scarr4(I_CLIENT=>200, O_CARRID => ?, O_CARRNAME => ?);
第2步:还需要设置SAPHANADB具有新建用户NewUser的执行权限:
第3步:开发ABAP程序,调用上述存储过程:
REPORT yz_demo7.
DATA: lv_carrid TYPE scarr-carrid,
lv_carrname TYPE scarr-carrname.
DATA: lv_exc_ref TYPE REF TO cx_sy_native_sql_error,
lv_error_text TYPE string.
TRY.
EXEC SQL.
EXECUTE PROCEDURE newuser.zp_scarr4 ( IN :sy-mandt, OUT :lv_carrid, OUT :lv_carrname )
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
CATCH cx_sy_native_sql_error INTO lv_exc_ref.
CLEAR: lv_error_text.
lv_error_text = lv_exc_ref->get_text( ).
MESSAGE lv_error_text TYPE 'I'.
ENDTRY.
WRITE: / lv_carrid, ' ', lv_carrname.
(8)调用自定义函数
第1步:在新建用户名NewUser对应Schema下,定义如下函数:
CREATE FUNCTION newuser.selfunc( mandt char(3), input CHAR(3) )
RETURNs output char(20) as
begin
SELECT carrname
INTO output
FROM saphanadb.scarr
WHERE mandt = mandt
AND carrid = input;
ENd;
--在Hana studio中调用函数
select newuser.selfunc( '200', 'AA') as carrname from dummy;
第2步:还需要设置SAPHANADB具有新建用户NewUser的查询权限:SELECT
第3步:开发ABAP程序,调用上述函数:
REPORT yz_demo8.
DATA: lv_carrid TYPE scarr-carrid VALUE 'AA',
lv_carrname TYPE scarr-carrname.
DATA: lv_exc_ref TYPE REF TO cx_sy_native_sql_error,
lv_error_text TYPE string.
TRY.
EXEC SQL.
select newuser.selfunc( :sy-mandt, :lv_carrid) into :lv_carrname from dummy;
ENDEXEC.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_native_sql_error.
ENDIF.
CATCH cx_sy_native_sql_error INTO lv_exc_ref.
CLEAR: lv_error_text.
lv_error_text = lv_exc_ref->get_text( ).
MESSAGE lv_error_text TYPE 'I'.
ENDTRY.
WRITE: / lv_carrid, ' ', lv_carrname.
方式二:ADBC
ADBC(ABAP Database Connectivity,ABAP 数据库链接)的本质就是Native SQL,只是用类做了封装,更加符合面向对象的开发理念,相对开发更友好一些。
SAP为大家提供了 Native SQL接口API,该接口主要由四个类组成:
• CL_SQL_STATEMENT - Execution of SQL Statements
• CL_SQL_PREPARED_STATEMENT - Prepared SQL Statements
• CL_SQL_CONNECTION - Administration of Database Connections
• CX_SQL_EXCEPTION - Exception Class
SAP系统自带的DEMO程序:
(9)ADBC示例
REPORT yz_demo9.
TYPES:BEGIN OF result_t,
ZNo TYPE i,
ZName TYPE string,
ZSex TYPE string,
ZAge TYPE i,
END OF result_t.
DATA:
* connection TYPE dbcon-con_name VALUE 'HAN',
stmt_ref TYPE REF TO cl_sql_statement,
cx_sql_exception TYPE REF TO cx_sql_exception,
lv_text TYPE string,
res_ref TYPE REF TO cl_sql_result_set,
d_ref TYPE REF TO data,
result_tab TYPE TABLE OF result_t,
result_line TYPE result_t,
row_cnt TYPE i,
con_ref TYPE REF TO cl_sql_connection.
con_ref = cl_sql_connection=>get_connection( ). "connection,不传参则使用系统当前链接
stmt_ref = con_ref->create_statement( ).
TRY.
stmt_ref->execute_ddl( 'create table saphanadb.ZStudent2( ZNo int,ZName nvarchar(10),ZSex nvarchar(1),ZAge int, primary key (ZNo) );').
stmt_ref->execute_update( 'insert into saphanadb.ZStudent2 values( 1, ''张三'', ''男'', 18 );' ).
stmt_ref->execute_update( 'insert into saphanadb.ZStudent2 values( 2, ''李四'', ''女'', 19 );').
stmt_ref->execute_update( 'update saphanadb.ZStudent2 set zsex = ''男'', zage = 18 where zname = ''李四'';' ).
stmt_ref->execute_update( 'delete from saphanadb.ZStudent2 where zname = ''张三'';' ).
res_ref = stmt_ref->execute_query( 'SELECT * FROM saphanadb.ZStudent2' ).
GET REFERENCE OF result_tab INTO d_ref.
res_ref->set_param_table( d_ref ).
row_cnt = res_ref->next_package( ).
stmt_ref->execute_ddl( 'DROP TABLE saphanadb.ZStudent2' ).
CATCH cx_sql_exception INTO cx_sql_exception.
lv_text = cx_sql_exception->get_text( ).
WRITE:/ 'Error:' , lv_text.
ENDTRY.
LOOP AT result_tab INTO result_line.
WRITE:/ 'NO:' , result_line-ZNo, ' NAME:', result_line-ZName, ' SEX:', result_line-ZSex, ' AGE:', result_line-ZAge.
ENDLOOP.
方式三:AMDP
AMDP(ABAP-Managed Database Procedure),就是在ABAP层进行HANA数据库过程的实现和生命周期的管理。ABAP开发人员可以在 Eclipse 中使用 ADT 开发工具来创建、更改或删除 AMDP方法,AMDP类作为其管理容器,可以使用ABAP 传输机制来管理。
AMDP支持ABAP开发人员在ADT工具中编写HANA SQLScrip,即所谓的数据库存储过程。
(10)编写SAP库存查询功能
实现步骤1:定义一个AMDP全局类
class YCL_AMDP_HDB_INVENTORY definition
public
final
create public .
PUBLIC SECTION.
INTERFACES IF_AMDP_MARKER_HDB . "集成系统AMDP接口
TYPES:
BEGIN OF TY_INVENTORY,
MATNR TYPE MATNR_D, "物料号
WERKS TYPE WERKS_D, "工厂
LGORT TYPE LGORT_D, "库存地点
SOBKZ TYPE SOBKZ, "特殊采购类型
CHARG TYPE CHARG_D, "批次
LIFNR TYPE LIFNR, "供应商
KUNNR TYPE KUNNR, "客户
VBELN TYPE VBELN, "销售凭证
POSNR TYPE POSNR, "销售凭证行项目
FQTY TYPE LABST, "库存量
END OF TY_INVENTORY .
TYPES:
TT_INVENTORY TYPE TABLE OF TY_INVENTORY WITH EMPTY KEY .
"AMDP PROCEDURE实现,直接写SQLScript从HDB获取数据,也可以调用已封装好的数据库存储过程
CLASS-METHODS GET_INVENTORY
IMPORTING
VALUE(P_CLNT) TYPE SY-MANDT
VALUE(p_MATNR) TYPE MATNR
VALUE(p_WERKS) TYPE WERKS_D
VALUE(p_LGORT) TYPE LGORT_D
VALUE(p_SOBKZ) TYPE SOBKZ
VALUE(p_CHARG) TYPE CHARG_D
VALUE(p_LIFNR) TYPE LIFNR
VALUE(p_KUNNR) TYPE KUNNR
VALUE(p_VBELN) TYPE VBELN
VALUE(p_POSNR) TYPE POSNR
EXPORTING
VALUE(ET_INVENTORY) TYPE TT_INVENTORY.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS YCL_AMDP_HDB_INVENTORY IMPLEMENTATION.
METHOD GET_INVENTORY
BY DATABASE PROCEDURE FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING NSDM_V_MCHB NSDM_V_mkol NSDM_V_MSKA
NSDM_V_MSLB NSDM_V_MCSD NSDM_V_MARD NSDM_V_MARC.
ET_INVENTORY =
SELECT
MATNR, WERKS, LGORT, '' AS SOBKZ, CHARG,
'' AS LIFNR, '' AS KUNNR, '' AS VBELN, '' AS POSNR,
CLABS AS FQTY
FROM NSDM_V_MCHB AS MCHB --MCHB-批次库存
WHERE CLABS <> 0
AND MANDT = :P_CLNT
AND ( MATNR = :p_MATNR OR :p_MATNR = '' )
AND ( WERKS = :p_WERKS or :p_WERKS = '' )
AND ( LGORT = :p_LGORT or :p_LGORT = '' )
AND ( CHARG = :p_CHARG or :p_CHARG = '' )
UNION
SELECT
MATNR, WERKS, LGORT, SOBKZ, CHARG,
LIFNR, '' as KUNNR, '' as VBELN, '' as POSNR, SLABS as FQTY
FROM NSDM_V_mkol as MKOL --MKOL-寄售库存
WHERE SLABS <> 0 and SOBKZ not in ( 'T', 'O' )
AND MANDT = :P_CLNT
AND ( MATNR = :p_MATNR or :p_MATNR = '' )
AND ( WERKS = :p_WERKS or :p_WERKS = '' )
AND ( LGORT = :p_LGORT or :p_LGORT = '' )
AND ( SOBKZ = :p_SOBKZ or :p_SOBKZ = '' )
AND ( CHARG = :p_CHARG or :p_CHARG = '' )
AND ( LIFNR = :p_LIFNR or :p_LIFNR = '' )
UNION
SELECT
MATNR, WERKS, LGORT, SOBKZ, CHARG,
'' as LIFNR, '' as KUNNR, VBELN, POSNR, KALAB as FQTY
from NSDM_V_MSKA as MSKA --MSKA-销售订单库存
where KALAB <> 0 and SOBKZ not in ( 'T', 'O' )
AND MANDT = :P_CLNT
AND ( MATNR = :p_MATNR or :p_MATNR = '' )
AND ( WERKS = :p_WERKS or :p_WERKS = '' )
AND ( LGORT = :p_LGORT or :p_LGORT = '' )
AND ( SOBKZ = :p_SOBKZ or :p_SOBKZ = '' )
AND ( CHARG = :p_CHARG or :p_CHARG = '' )
AND ( VBELN = :p_VBELN or :p_VBELN = '' )
AND ( POSNR = :p_POSNR or :p_POSNR = '000000' )
UNION
SELECT
MATNR, WERKS, '' as LGORT, SOBKZ, CHARG,
LIFNR, '' as KUNNR, '' as VBELN, '' as POSNR, LBLAB as FQTY
from NSDM_V_MSLB as MSLB --MSLB-供应商外包库存
where LBLAB <> 0 and SOBKZ not in ( 'T', 'O' )
AND MANDT = :P_CLNT
AND ( MATNR = :p_MATNR or :p_MATNR = '' )
AND ( WERKS = :p_WERKS or :p_WERKS = '' )
AND ( SOBKZ = :p_SOBKZ or :p_SOBKZ = '' )
AND ( CHARG = :p_CHARG or :p_CHARG = '' )
AND ( LIFNR = :p_LIFNR or :p_LIFNR = '' )
--* and LGORT in @LR_LGORT
UNION
SELECT
MATNR, WERKS, LGORT, SOBKZ, CHARG,
'' as LIFNR, KUNNR, '' as VBELN, '' as POSNR, SDLAB as FQTY
from NSDM_V_MCSD as MCSD --MCSD-客户库存
where SDLAB <> 0 and SOBKZ not in ( 'T', 'O' )
AND MANDT = :P_CLNT
AND ( MATNR = :p_MATNR or :p_MATNR = '' )
AND ( WERKS = :p_WERKS or :p_WERKS = '' )
AND ( LGORT = :p_LGORT or :p_LGORT = '' )
AND ( SOBKZ = :p_SOBKZ or :p_SOBKZ = '' )
AND ( CHARG = :p_CHARG or :p_CHARG = '' )
AND ( KUNNR = :p_KUNNR or :p_KUNNR = '' )
UNION
SELECT
MARD.MATNR, MARD.WERKS, MARD.LGORT, '' as SOBKZ, '' as CHARG,
'' as LIFNR, '' as KUNNR, '' as VBELN, '' as POSNR, MARD.LABST AS FQTY
FROM NSDM_V_MARD AS MARD --MARD-仓库库存
INNER JOIN NSDM_V_MARC as MARC ON MARD.MATNR = MARC.MATNR AND MARC.WERKS = MARD.WERKS AND MARD.MANDT = MARC.MANDT
WHERE MARD.LABST <> 0
AND MARD.MANDT = :P_CLNT
AND MARC.XCHAR = ''
AND ( MARD.MATNR = :p_MATNR or :p_MATNR = '' )
AND ( MARD.WERKS = :p_WERKS or :p_WERKS = '' )
AND ( MARD.LGORT = :p_LGORT or :p_LGORT = '' )
;
ENDMETHOD.
ENDCLASS.
实现步骤2:定义一个ABAP程序来调用AMDP全局类
*&---------------------------------------------------------------------*
*& Report YZ_AMDP_DEMO
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT yz_amdp_demo.
TYPES:
BEGIN OF ty_inventory,
matnr TYPE matnr_d, "物料号
werks TYPE werks_d, "工厂
lgort TYPE lgort_d, "库存地点
sobkz TYPE sobkz, "特殊采购类型
charg TYPE charg_d, "批次
lifnr TYPE lifnr, "供应商
kunnr TYPE kunnr, "客户
vbeln TYPE vbeln, "销售凭证
posnr TYPE posnr, "销售凭证行项目
fqty TYPE labst, "库存量
END OF ty_inventory .
TYPES:
tt_inventory TYPE TABLE OF ty_inventory WITH EMPTY KEY .
DATA: gt_inventory TYPE tt_inventory.
DATA: iv_matnr TYPE matnr,
iv_werks TYPE werks_d,
iv_lgort TYPE lgort_d,
iv_sobkz TYPE sobkz,
iv_charg TYPE charg_d,
iv_lifnr TYPE lifnr,
iv_kunnr TYPE kunnr,
iv_vbeln TYPE vbeln,
iv_posnr TYPE posnr.
DATA: gt_fieldcat TYPE lvc_t_fcat WITH HEADER LINE. " 字段目录
START-OF-SELECTION.
IF cl_abap_dbfeatures=>use_features(
EXPORTING
requested_features = VALUE #( ( cl_abap_dbfeatures=>call_amdp_method )
( cl_abap_dbfeatures=>amdp_table_function ) ) ).
TRY ."异常捕捉
ycl_amdp_hdb_inventory=>get_inventory(
EXPORTING
p_clnt = sy-mandt
p_matnr = iv_matnr
p_werks = iv_werks
p_lgort = iv_lgort
p_sobkz = iv_sobkz
p_charg = iv_charg
p_lifnr = iv_lifnr
p_kunnr = iv_kunnr
p_vbeln = iv_vbeln
p_posnr = iv_posnr
IMPORTING
et_inventory = gt_inventory ).
CATCH cx_ai_system_fault INTO DATA(zcl_cx_ai_system_fault).
* EV_STATUS = 'E'.
* EV_MESSAGE = ZCL_CX_AI_SYSTEM_FAULT->GET_TEXT( ).
EXIT.
CATCH cx_ai_application_fault INTO DATA(zcl_cx_ai_application_fault).
* EV_STATUS = 'E'.
* EV_MESSAGE = ZCL_CX_AI_APPLICATION_FAULT->GET_TEXT( ).
EXIT.
ENDTRY.
"cl_demo_output=>display( GT_INVENTORY ). " 报错,改用ALV显示
PERFORM frm_alv_show.
ELSE.
cl_demo_output=>display( '警告!当前系统不支持AMDP.' ).
ENDIF.
FORM frm_alv_show .
DATA: w_layout TYPE lvc_s_layo.
CLEAR w_layout.
w_layout-zebra = 'X'.
w_layout-col_opt = 'X'.
PERFORM frm_build_fieldcat.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
i_callback_program = sy-repid
is_layout_lvc = w_layout
it_fieldcat_lvc = gt_fieldcat[]
* i_default = 'X'
* i_save = 'A'
TABLES
t_outtab = gt_inventory
EXCEPTIONS
program_error = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM. " FRM_ALV_SHOW
FORM frm_build_fieldcat.
DEFINE mac_field.
gt_fieldcat-fieldname = &1. " 内表字段名
gt_fieldcat-reptext = &2.
APPEND gt_fieldcat.
end-OF-DEFINITION.
mac_field: 'MATNR' '物料号',
'WERKS' '工厂',
'LGORT' '库存地点',
'SOBKZ' '特殊采购类型',
'CHARG' '批次',
'LIFNR' '供应商',
'KUNNR' '客户',
'VBELN' '销售凭证',
'POSNR' '销售凭证行项目',
'FQTY' '库存量'.
ENDFORM.
更多详细介绍,请参考待发布的专题文章《SAP AMDP实现方法简介》。
原创文章,转载请注明来源-X档案