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

SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)

  • 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库存查询功能
    • 方法四:SALV IDA
      • (11)一句语句实现ALV

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

1、SAP Open SQL 与 Native SQL 的特点

在 ABAP/4 编程语言中,提供了两种类型的 SQL。

第一种:Open SQL
【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第1张图片
(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
【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第2张图片
(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的数据:
【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第3张图片

(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.

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

(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.

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

(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.

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

(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.

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

(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( ).

【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第8张图片
【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第9张图片

(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, '位。' .

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

(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 => ?);

【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第11张图片
【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第12张图片
第2步:还需要设置SAPHANADB具有新建用户NewUser的执行权限:
【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第13张图片
第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.

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

(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;

【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第15张图片
第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.

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

方式二:类方法 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程序:
【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第17张图片

(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.

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

方式三: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 ABAP 中 AMDP 简介及实现方法》。

方法四:SALV IDA

(11)一句语句实现ALV

首先定义CDS视图:

@AbapCatalog.sqlViewName: 'YV_DEMO01_SCARR'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO01_SCARR'
define view YCDS_DEMO01_SCARR as 
select from scarr
{
    --key mandt,    -- CDS会自动添加
    key carrid,
        carrname,
        url
};

一句语句展示ALV:

REPORT YZ_SALV_DEMO.
CL_SALV_GUI_TABLE_IDA=>CREATE_FOR_CDS_VIEW( iv_cds_view_name = 'YCDS_DEMO01_SCARR' )->FULLSCREEN( )->DISPLAY( ).

运行程序如下:
【SAP Abap】X档案:SAP Native SQL 简介及本地数据库访问实现方式(EXEC SQL、ADBC、AMDP、IDA)_第19张图片

原创文章,转载请注明来源-X档案

你可能感兴趣的:(SAP,Hana,SAP,Abap,sql,数据库)