【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP)

news2024/10/7 4:26:57

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库存查询功能

在SAP S4系统中,提供了多种方式来实现本地数据库访问,如:OPENSQL、NativeSQL、ADBC、AMDP等。

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,即所谓的数据库存储过程。

使用ABAP Managed Database Procedure(AMDP)和CDS开发,属于自上而下的ABAP for HANA开发方式。在应用层即ABAP程序中管理数据计算逻辑和建模,激活后会在HANA中创建相应的数据库对象。相比于旧有的Database Procedure Proxy,AMDP提供了简单的调用SQL Script等数据库语言的方式。

(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档案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/173126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iOS上架appstore详细教材

假如你用原生xcode开发&#xff0c;上架是相对简单。 但假如是用hbuilderx这些uniapp框架开发&#xff0c;没有mac电脑&#xff0c;没有xcode&#xff0c;那么还能上架吗&#xff1f;是可以的&#xff0c;你看完这篇文章&#xff0c;就知道如何在没有mac电脑的情况下&#xff…

【小知识】目标检测各类指标概念总结

文章目录前言一、AP&#xff08;Average Precision&#xff09;1.1 TP&#xff08;True Positive&#xff09;、FP&#xff08;False Positive&#xff09;、FN&#xff08;False Negative&#xff09;1.2 Precision&#xff08;查准率&#xff09;、Recall&#xff08;召回率/…

【LeetCode】Day201-重新安排行程

题目 332.重新安排行程【困难】 题解 这道题的几个难点&#xff1a; 一个行程中&#xff0c;如果航班处理不好容易变成一个圈&#xff0c;成为死循环有多种解法&#xff0c;字母序靠前排在前面&#xff0c;应该如何记录映射关系&#xff1f;使用回溯法&#xff0c;终止条件…

贪心 376. 摆动序列

376. 摆动序列 难度中等827 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。 例如&#xff0c; [1, 7, 4, 9,…

opencv的图像基本操作_3

模板匹配 模板匹配和卷积很像&#xff0c;模板在原图像上滑动&#xff0c;并在滑过的区域上计算匹配数值&#xff0c;通过匹配数值衡量模板匹配程度&#xff0c;opencv中有6种计算方法&#xff0c;从原点开始计算&#xff0c;将每次计算的结果放到一个矩阵&#xff0c;最后输出…

CSS 加载进度条

CSS 加载进度条 环形加载条 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>环形加载条</title><style type"text/css">.box {width: 200px;height: 200px;border: 1px solid silver;display: flex…

永磁同步电机全速域控制指南

一直都想知道永磁同步电机的转速从零增加到极限这个过程会发生什么&#xff0c;这篇文章介绍一下永磁同步电机全速域矢量控制的全过程&#xff0c;即电机的转速从零开始逐渐增加&#xff0c;如何设计电流环电流使得电机输出恒定转矩&#xff0c;且保持转速稳定。能把这个过程想…

ruoyi-vue版本(七)定时任务 相关的源码解析,也就是ruoyi-quartz 模块的解析

目录1 需求2 解析2.1 工具类里面的关系2.2 新增定时任务2.3 回显定时任务2.4 修改定时任务3 总结1 需求 我们打开若依项目&#xff0c;看到页面上有一个定时任务模块 我们接下来就是解析若依项目和定时任务相关的所有的文件&#xff0c;以及他是如何实现定时的&#xff0c;背…

Kubernetes 资源监控

Kubernetes 资源监控一、前言二、使用三、实现原理3.1 数据链路3.2 kube-aggregator3.3 监控体系 ❤️3.4 kubelet3.5 cadvisor3.6 cgroup四、问题4.2 kubectl top pod 内存怎么计算&#xff0c;包含 pause容器吗4.3 kubectl top node 怎么计算&#xff0c;和节点上直接 top 有…

C语言深度剖析 -- 32个关键字(上)

文章目录C语言关键字我们人生中第一个C语言程序变量的定义与声明变量的作用域与生命周期最宽宏大量的关键字 -- auto最快的关键字 -- register&#xff08;寄存器变量&#xff09;最名不符实的关键字 -- static基本内置数据类型 -- char、short、int、long、float、double最冤枉…

transformers学习笔记2

pipeline快速使用from transformers import pipelineclassifier pipeline("sentiment-analysis") classifier(["Ive been waiting for a HuggingFace course my whole life.","I hate this so much!",] )[{label: POSITIVE, score: 0.959804713…

概述.runoob.html

<!DOCTYPE html> 声明为 HTML5 文档<html> 元素是 HTML 页面的根元素<head> 元素包含了文档的元&#xff08;meta&#xff09;数据&#xff0c;如 <meta charset"utf-8"> 定义网页编码格式为 utf-8。<title> 元素描述了文档的标题<…

【Linux线程安全】

Linux线程安全Linux线程互斥进程线程间的互斥相关背景概念互斥量mutex互斥量的接口互斥量实现原理探究可重入VS线程安全概念常见的线程不安全的情况常见的线程安全的情况常见的不可重入的情况常见的可重入的情况可重入与线程安全联系可重入与线程安全区别常见锁概念死锁死锁的四…

套接字编程基础

文章目录IPV4套接字地址结构IPv6套接字地址结构字节排序函数地址转换函数IPV4套接字地址结构 IPv4套接字定义在<netinet/in.h> 投文件中&#xff0c;定义如下&#xff1a; struct in_addr {in_addr_t s_addr; } struct sockaddr_in {uint8_t sin_len; // 长度字段sa_fa…

【青训营】性能优化和自动内存管理

本文整理自&#xff1a;第五届字节跳动青年训练营 后端组 什么是性能优化 提高软件系统处理能力&#xff0c;减少不必要消耗&#xff0c;充分利用计算机算力 业务层优化 针对特定场景和具体问题容易获得较大收益 语言运行时优化 面向全公司的优化&#xff0c;非特定场景解决更…

力扣55.跳跃游戏(比较简单)

文章目录力扣55.跳跃游戏&#xff08;比较简单&#xff09;题目描述算法思路代码实现力扣55.跳跃游戏&#xff08;比较简单&#xff09; 题目描述 给定一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度…

Tailscale-搭建异地局域网开源版中文部署指南

目前国家工信部在大力推动三大运营商发展 IPv6&#xff0c;对家用宽带而言&#xff0c;可以使用的 IPv4 公网 IP 会越来越少。有部分地区即使拿到了公网 IPv4 地址&#xff0c;也是个大内网地址&#xff0c;根本不是真正的公网 IP&#xff0c;访问家庭内网的资源将会变得越来越…

SQL注入之联合查询注入与报错注入

数据来源 本文仅用于信息安全的学习&#xff0c;请遵守相关法律法规&#xff0c;严禁用于非法途径。若观众因此作出任何危害网络安全的行为&#xff0c;后果自负&#xff0c;与本人无关。 SQL注入之联合查询 sql注入简单演示 1. 判断sq注入 2. 闭合然后爆列 3. 查看显示列 …

vue中实现后台系统权限管理的功能

一、前言 后台管理系统的权限控制对于前端来说是经常用到的知识点&#xff0c;也比较重要&#xff0c;最近梳理一下写成文章&#xff0c;方便以后查阅。 项目中实现菜单的动态权限控制使用到了两种技术&#xff0c;一种是Vue Router&#xff0c;另一种是vue3官方推荐使用的专属…

蓝桥杯嵌入式第十届学习记录

1&#xff1a;拷贝LCD工程代码作为模板2&#xff1a;注意放置代码得顺序3&#xff1a;注意公共头函数键盘4&#xff1a;串口配置出来方便dubug模式正常接收数据5:记得打定时器中断&#xff08;去历程定时器里面寻找&#xff01;&#xff09;6&#xff1a;细节地方7;LCD每个位置…