SAP<->SQL server链接

把SAP的表推送到SQL SERVER

  1. 配置数据库连接 (T-Code: DBCO):

登录 SAP,运行事务码 DBCO 或 DBA_COCKPIT。

点击"新条目"创建一个新连接(例如命名为 SQL_SERVER_DB)。

DBMS: 选择 MSS (代表 Microsoft SQL Server)。

用户名/密码: 输入拥有 SQL Server 读写权限的账号密码。

连接信息: 输入类似 MSSQL_SERVER=你的服务器IP MSSQL_DBNAME=你的数据库名。

推送类方法:

css 复制代码
CLASS zcl_sql_server_gateway DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    " 构造函数:默认连接名 ZMSS
    METHODS constructor
      IMPORTING iv_dbcon_name TYPE dbcon-con_name DEFAULT 'ZMSS'
      RAISING   cx_sql_exception.

    " 1. 动态查询 (Read)
    METHODS execute_query
      IMPORTING iv_sql        TYPE string
      EXPORTING et_result_tab TYPE ANY TABLE
      RAISING   cx_sql_exception.

    " 2. 批量增量推送 (Upsert: Create/Update)
    METHODS push_data_upsert
      IMPORTING
        iv_interface_id TYPE char32
        iv_target_table TYPE string
        it_key_fields   TYPE string_table
        it_data         TYPE ANY TABLE
      RETURNING
        VALUE(rv_rows)  TYPE i
      RAISING
        cx_sql_exception
        cx_parameter_invalid.

    " 3. 通用 DML 执行 (适用于简单的 DELETE/UPDATE 语句)
    METHODS execute_dml
      IMPORTING iv_sql         TYPE string
      RETURNING VALUE(rv_rows) TYPE i
      RAISING   cx_sql_exception.

    " 4. 基于内表的批量删除 (Delete) - 极速模式
    METHODS delete_by_itab
      IMPORTING
        iv_target_table TYPE string
        it_key_fields   TYPE string_table
        it_data         TYPE ANY TABLE
      RETURNING
        VALUE(rv_rows)  TYPE i
      RAISING
        cx_sql_exception
        cx_parameter_invalid.

    " 5. 获取增量水位线
    METHODS get_watermark
      IMPORTING iv_interface_id TYPE char32
      RETURNING VALUE(rv_tstmp) TYPE timestampl.

    " 6. 关闭连接
    METHODS close_connection
      RAISING cx_sql_exception.

  PRIVATE SECTION.
    DATA mo_conn TYPE REF TO cl_sql_connection.

    " 更新同步水位线
    METHODS update_watermark
      IMPORTING iv_interface_id TYPE char32.
ENDCLASS.



CLASS ZCL_SQL_SERVER_GATEWAY IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_SQL_SERVER_GATEWAY->CLOSE_CONNECTION
* +-------------------------------------------------------------------------------------------------+
* | [!CX!] CX_SQL_EXCEPTION
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD close_connection.
    IF mo_conn IS BOUND.
      mo_conn->close( ).
      CLEAR mo_conn.
    ENDIF.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_SQL_SERVER_GATEWAY->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_DBCON_NAME                  TYPE        DBCON-CON_NAME (default ='ZMSS')
* | [!CX!] CX_SQL_EXCEPTION
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD constructor.
    mo_conn = cl_sql_connection=>get_connection( iv_dbcon_name ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_SQL_SERVER_GATEWAY->DELETE_BY_ITAB
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_TARGET_TABLE                TYPE        STRING
* | [--->] IT_KEY_FIELDS                  TYPE        STRING_TABLE
* | [--->] IT_DATA                        TYPE        ANY TABLE
* | [<-()] RV_ROWS                        TYPE        I
* | [!CX!] CX_SQL_EXCEPTION
* | [!CX!] CX_PARAMETER_INVALID
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD delete_by_itab.
    CHECK it_data IS NOT INITIAL.

    DATA(lo_table_desc)  = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( it_data ) ).
    DATA(lo_struct_desc) = CAST cl_abap_structdescr( lo_table_desc->get_table_line_type( ) ).
    DATA(lt_fields)      = lo_struct_desc->get_components( ).

    DATA(lv_field_list) = REDUCE string( INIT s = `` FOR ls IN lt_fields
                                         NEXT s = COND #( WHEN s IS INITIAL THEN |[{ ls-name }]| ELSE s && |, [{ ls-name }]| ) ).

    DATA(lv_temp_table) = |#DEL_{ iv_target_table }|.
    mo_conn->create_statement( )->execute_update( |SELECT TOP 0 { lv_field_list } INTO { lv_temp_table } FROM { iv_target_table }| ).

    DATA(lv_marks) = REDUCE string( INIT m = `` FOR i = 1 UNTIL i > lines( lt_fields )
                                    NEXT m = COND #( WHEN m IS INITIAL THEN `?` ELSE m && `, ?` ) ).

    DATA(lo_ins_stmt) = mo_conn->create_statement( ).
    lo_ins_stmt->set_param_table( table_ref = REF #( it_data ) ).
    lo_ins_stmt->execute_update( |INSERT INTO { lv_temp_table } ({ lv_field_list }) VALUES ({ lv_marks })| ).

    DATA(lv_where) = REDUCE string( INIT c = `` FOR k IN it_key_fields
                                    NEXT c = COND #( WHEN c IS INITIAL THEN |T.[{ k }] = S.[{ k }]| ELSE |{ c } AND T.[{ k }] = S.[{ k }]| ) ).

    " SQL Server 关联删除语法
    DATA(lv_del_sql) = |DELETE T FROM { iv_target_table } AS T INNER JOIN { lv_temp_table } AS S ON { lv_where }|.
    rv_rows = mo_conn->create_statement( )->execute_update( lv_del_sql ).

    mo_conn->create_statement( )->execute_update( |DROP TABLE { lv_temp_table }| ).
    mo_conn->commit( ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_SQL_SERVER_GATEWAY->EXECUTE_DML
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_SQL                         TYPE        STRING
* | [<-()] RV_ROWS                        TYPE        I
* | [!CX!] CX_SQL_EXCEPTION
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD execute_dml.
    rv_rows = mo_conn->create_statement( )->execute_update( iv_sql ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_SQL_SERVER_GATEWAY->EXECUTE_QUERY
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_SQL                         TYPE        STRING
* | [<---] ET_RESULT_TAB                  TYPE        ANY TABLE
* | [!CX!] CX_SQL_EXCEPTION
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD execute_query.
    DATA(lo_stmt) = mo_conn->create_statement( ).
    DATA(lo_res)  = lo_stmt->execute_query( iv_sql ).
    " 注意:结果集对象使用 itab_ref
    lo_res->set_param_table( itab_ref = REF #( et_result_tab ) ).
    lo_res->next_package( ).
    lo_res->close( ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_SQL_SERVER_GATEWAY->GET_WATERMARK
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_INTERFACE_ID                TYPE        CHAR32
* | [<-()] RV_TSTMP                       TYPE        TIMESTAMPL
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_watermark.
    SELECT SINGLE last_sync_tstmp FROM ztb_sync_log
      WHERE interface_id = @iv_interface_id INTO @rv_tstmp.
    IF sy-subrc <> 0.
      rv_tstmp = '19700101000000'.
    ENDIF.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_SQL_SERVER_GATEWAY->PUSH_DATA_UPSERT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_INTERFACE_ID                TYPE        CHAR32
* | [--->] IV_TARGET_TABLE                TYPE        STRING
* | [--->] IT_KEY_FIELDS                  TYPE        STRING_TABLE
* | [--->] IT_DATA                        TYPE        ANY TABLE
* | [<-()] RV_ROWS                        TYPE        I
* | [!CX!] CX_SQL_EXCEPTION
* | [!CX!] CX_PARAMETER_INVALID
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD push_data_upsert.
    CHECK it_data IS NOT INITIAL.

    " RTTI 解析结构
    DATA(lo_table_desc)  = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( it_data ) ).
    DATA(lo_struct_desc) = CAST cl_abap_structdescr( lo_table_desc->get_table_line_type( ) ).
    DATA(lt_fields)      = lo_struct_desc->get_components( ).

    " 构建字段列表 CSV
    DATA(lv_field_list) = REDUCE string( INIT s = `` FOR ls IN lt_fields
                                         NEXT s = COND #( WHEN s IS INITIAL THEN |[{ ls-name }]| ELSE s && |, [{ ls-name }]| ) ).

    " A. 创建会话级临时表
    DATA(lv_temp_table) = |#TMP_{ iv_target_table }|.
    mo_conn->create_statement( )->execute_update( |SELECT TOP 0 { lv_field_list } INTO { lv_temp_table } FROM { iv_target_table }| ).

    " B. 批量插入到临时表
    DATA(lv_marks) = REDUCE string( INIT m = `` FOR i = 1 UNTIL i > lines( lt_fields )
                                    NEXT m = COND #( WHEN m IS INITIAL THEN `?` ELSE m && `, ?` ) ).
    DATA(lo_insert_stmt) = mo_conn->create_statement( ).
    " 注意:执行对象使用 table_ref
    lo_insert_stmt->set_param_table( table_ref = REF #( it_data ) ).
    lo_insert_stmt->execute_update( |INSERT INTO { lv_temp_table } ({ lv_field_list }) VALUES ({ lv_marks })| ).

    " C. 构造 MERGE 逻辑 (处理主键排除)
    DATA(lv_on_cond) = REDUCE string( INIT c = `` FOR k IN it_key_fields
                                      NEXT c = COND #( WHEN c IS INITIAL THEN |T.[{ k }] = S.[{ k }]| ELSE |{ c } AND T.[{ k }] = S.[{ k }]| ) ).

    DATA(lv_update_fields) = ``.
    LOOP AT lt_fields ASSIGNING FIELD-SYMBOL(<ls_f>).
      READ TABLE it_key_fields WITH KEY table_line = <ls_f>-name TRANSPORTING NO FIELDS.
      IF sy-subrc <> 0.
        lv_update_fields = COND #( WHEN lv_update_fields IS INITIAL THEN |T.[{ <ls_f>-name }] = S.[{ <ls_f>-name }]|
                                   ELSE |{ lv_update_fields }, T.[{ <ls_f>-name }] = S.[{ <ls_f>-name }]| ).
      ENDIF.
    ENDLOOP.

    DATA(lv_insert_vals) = REDUCE string( INIT v = `` FOR ls IN lt_fields
                                          NEXT v = COND #( WHEN v IS INITIAL THEN |S.[{ ls-name }]| ELSE |{ v }, S.[{ ls-name }]| ) ).

    " D. 执行 MERGE
    DATA(lv_merge_sql) = |MERGE INTO { iv_target_table } AS T | &&
                         |USING { lv_temp_table } AS S ON ({ lv_on_cond }) | &&
                         |WHEN MATCHED THEN UPDATE SET { lv_update_fields } | &&
                         |WHEN NOT MATCHED THEN INSERT ({ lv_field_list }) VALUES ({ lv_insert_vals });|.

    rv_rows = mo_conn->create_statement( )->execute_update( lv_merge_sql ).
    mo_conn->create_statement( )->execute_update( |DROP TABLE { lv_temp_table }| ).

    update_watermark( iv_interface_id ).
    mo_conn->commit( ).
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_SQL_SERVER_GATEWAY->UPDATE_WATERMARK
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_INTERFACE_ID                TYPE        CHAR32
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD update_watermark.
    GET TIME STAMP FIELD DATA(lv_now).
    MODIFY ztb_sync_log FROM @( VALUE #( interface_id = iv_interface_id last_sync_tstmp = lv_now last_user = sy-uname ) ).
  ENDMETHOD.
ENDCLASS.

推送表示例程序:

css 复制代码
REPORT zfi_tables_post.

TABLES: zfit046,
        zfit047,
        zfit048.

SELECTION-SCREEN BEGIN OF BLOCK blk1 WITH FRAME TITLE TEXT-001.
  PARAMETERS: p_gjahr TYPE gjahr OBLIGATORY DEFAULT sy-datum+0(4).
  PARAMETERS: p_full  TYPE char1 DEFAULT ' '.
SELECTION-SCREEN END OF BLOCK blk1.

INITIALIZATION.
  IF sy-langu NE '1'.
    PERFORM mod_sel_text USING sy-repid 'P' 'P_GJAHR' 'Fiscal Year'.
    PERFORM mod_sel_text USING sy-repid 'P' 'P_FULL'  'Full Load(X=Full, blank=Current Year)'.
  ENDIF.

START-OF-SELECTION.
  PERFORM frm_push_zfit046.
  PERFORM frm_push_zfit047.
  PERFORM frm_push_zfit048.

*----------------------------------------------------------------------*
FORM frm_push_zfit046.

  DATA: lo_gateway TYPE REF TO zcl_sql_server_gateway.
  DATA: lt_zfit046 TYPE STANDARD TABLE OF zfit046.
  DATA: lv_del_sql TYPE string.

  IF p_full = 'X'.
    SELECT *
      INTO CORRESPONDING FIELDS OF TABLE @lt_zfit046
      FROM zfit046.
  ELSE.
    SELECT *
      INTO CORRESPONDING FIELDS OF TABLE @lt_zfit046
      FROM zfit046
     WHERE gjahr = @p_gjahr.
  ENDIF.

  IF lt_zfit046 IS INITIAL.
    MESSAGE 'ZFIT046 no data!' TYPE 'S' DISPLAY LIKE 'W'.
    RETURN.
  ENDIF.

  TRY.
      lo_gateway = NEW zcl_sql_server_gateway( 'ZMSS' ).

      IF p_full = 'X'.
        lv_del_sql = |DELETE FROM ZFIT046|.
      ELSE.
        lv_del_sql = |DELETE FROM ZFIT046 WHERE GJAHR = '{ p_gjahr }'|.
      ENDIF.

      lo_gateway->execute_dml( lv_del_sql ).

      lo_gateway->push_data_upsert(
        iv_interface_id = 'INT_FI_BS'
        iv_target_table = 'ZFIT046'
        it_key_fields   = VALUE string_table(
                            ( `MANDT`  )
                            ( `BUKRS`  )
                            ( `GJAHR`  )
                            ( `ZSEQNO` )
                          )
        it_data         = lt_zfit046
      ).

      MESSAGE |ZFIT046 pushed { lines( lt_zfit046 ) } rows successfully!| TYPE 'S'.

    CATCH cx_root INTO DATA(lx_ex).
      MESSAGE |ZFIT046 push failed: { lx_ex->get_text( ) }| TYPE 'E'.

  ENDTRY.

ENDFORM.

*----------------------------------------------------------------------*
FORM frm_push_zfit047.

  DATA: lo_gateway TYPE REF TO zcl_sql_server_gateway.
  DATA: lt_zfit047 TYPE STANDARD TABLE OF zfit047.
  DATA: lv_del_sql TYPE string.

  IF p_full = 'X'.
    SELECT *
      INTO CORRESPONDING FIELDS OF TABLE @lt_zfit047
      FROM zfit047.
  ELSE.
    SELECT *
      INTO CORRESPONDING FIELDS OF TABLE @lt_zfit047
      FROM zfit047
     WHERE gjahr = @p_gjahr.
  ENDIF.

  IF lt_zfit047 IS INITIAL.
    MESSAGE 'ZFIT047 no data!' TYPE 'S' DISPLAY LIKE 'W'.
    RETURN.
  ENDIF.

  TRY.
      lo_gateway = NEW zcl_sql_server_gateway( 'ZMSS' ).

      IF p_full = 'X'.
        lv_del_sql = |DELETE FROM ZFIT047|.
      ELSE.
        lv_del_sql = |DELETE FROM ZFIT047 WHERE GJAHR = '{ p_gjahr }'|.
      ENDIF.

      lo_gateway->execute_dml( lv_del_sql ).

      lo_gateway->push_data_upsert(
        iv_interface_id = 'INT_FI_IS'
        iv_target_table = 'ZFIT047'
        it_key_fields   = VALUE string_table(
                            ( `MANDT`  )
                            ( `BUKRS`  )
                            ( `GJAHR`  )
                            ( `ZSEQNO` )
                          )
        it_data         = lt_zfit047
      ).

      MESSAGE |ZFIT047 pushed { lines( lt_zfit047 ) } rows successfully!| TYPE 'S'.

    CATCH cx_root INTO DATA(lx_ex).
      MESSAGE |ZFIT047 push failed: { lx_ex->get_text( ) }| TYPE 'E'.

  ENDTRY.

ENDFORM.

*----------------------------------------------------------------------*
FORM frm_push_zfit048.

  DATA: lo_gateway TYPE REF TO zcl_sql_server_gateway.
  DATA: lt_zfit048 TYPE STANDARD TABLE OF zfit048.
  DATA: lv_del_sql TYPE string.

  IF p_full = 'X'.
    SELECT *
      INTO CORRESPONDING FIELDS OF TABLE @lt_zfit048
      FROM zfit048.
  ELSE.
    SELECT *
      INTO CORRESPONDING FIELDS OF TABLE @lt_zfit048
      FROM zfit048
     WHERE gjahr = @p_gjahr.
  ENDIF.

  IF lt_zfit048 IS INITIAL.
    MESSAGE 'ZFIT048 no data!' TYPE 'S' DISPLAY LIKE 'W'.
    RETURN.
  ENDIF.

  TRY.
      lo_gateway = NEW zcl_sql_server_gateway( 'ZMSS' ).

      IF p_full = 'X'.
        lv_del_sql = |DELETE FROM ZFIT048|.
      ELSE.
        lv_del_sql = |DELETE FROM ZFIT048 WHERE GJAHR = '{ p_gjahr }'|.
      ENDIF.

      lo_gateway->execute_dml( lv_del_sql ).

      lo_gateway->push_data_upsert(
        iv_interface_id = 'INT_FI_CF'
        iv_target_table = 'ZFIT048'
        it_key_fields   = VALUE string_table(
                            ( `MANDT`  )
                            ( `BUKRS`  )
                            ( `GJAHR`  )
                            ( `ZSEQNO` )
                          )
        it_data         = lt_zfit048
      ).

      MESSAGE |ZFIT048 pushed { lines( lt_zfit048 ) } rows successfully!| TYPE 'S'.

    CATCH cx_root INTO DATA(lx_ex).
      MESSAGE |ZFIT048 push failed: { lx_ex->get_text( ) }| TYPE 'E'.

  ENDTRY.

ENDFORM.

*----------------------------------------------------------------------*
FORM mod_sel_text USING p_repid kind parameter text.
  DATA sel TYPE rsseltexts OCCURS 1 WITH HEADER LINE.
  REFRESH sel.
  sel-name = parameter.
  sel-kind = kind.
  sel-text = text.
  APPEND sel.
  CALL FUNCTION 'SELECTION_TEXTS_MODIFY'
    EXPORTING
      program                     = p_repid
    TABLES
      seltexts                    = sel
    EXCEPTIONS
      program_not_found           = 1
      program_cannot_be_generated = 2
      OTHERS                      = 3.
  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.

ALV推送示例:

css 复制代码
 IF sy-batch = 'X' AND  sy-uname = 'JOB' .
    PERFORM frm_push_zmmt058.
 endif.
 DATA: lo_gateway TYPE REF TO zcl_sql_server_gateway.
  DATA: lv_del_sql TYPE string.
  DATA: gt_out1 TYPE TABLE OF zmms058a_ss.

  IF gt_out IS INITIAL.
    MESSAGE 'No Data!' TYPE 'S' DISPLAY LIKE 'W'.
    RETURN.
  ENDIF.

  MOVE-CORRESPONDING gt_out TO gt_out1.

  TRY.
      lo_gateway = NEW zcl_sql_server_gateway( 'ZMSS' ).

      lv_del_sql = |DELETE FROM ZMMT058|.

      lo_gateway->execute_dml( lv_del_sql ).

      lo_gateway->push_data_upsert(
        iv_interface_id = 'INT_MES_BS'
        iv_target_table = 'ZMMT058'
        it_key_fields   = VALUE string_table(
                            ( `WERKS`  )
                            ( `EBELN`  )
                            ( `EBELP`  )
                            ( `EBELN1`  )
                            ( `MATNR` )
                          )
        it_data         = gt_out1
      ).

      MESSAGE |ZMMT058 pushed { lines( gt_out1 ) } rows successfully!| TYPE 'S'.

    CATCH cx_root INTO DATA(lx_ex).
      MESSAGE |ZMMT058 push failed: { lx_ex->get_text( ) }| TYPE 'E'.

  ENDTRY.
相关推荐
Slow、1 天前
PPDS生产计划排产-MRP运行
sap·apo
星光不负赶路人!1 天前
【工作记录】sqlserver数据库操作及迁移
服务器·数据库·sqlserver
_1_73 天前
SQL Server 磁盘满了 收缩日志
数据库·sqlserver
满昕欢喜3 天前
第2章 SQL Server 2019服务器管理
数据库·sqlserver
淘源码d3 天前
医院专业级PACS系统完整源码(C+VC+MSSQL)
c语言·数据库·sqlserver·源码·pacs系统·医学影像系统
爱喝水的鱼丶4 天前
SAP-ABAP:SAP基础数据校验工具开发系列博客(共5篇)第五篇:性能优化与上线运维:保障高并发场景下的工具稳定运行
运维·学习·性能优化·sap·abap·erp·经验交流
woshilys4 天前
sql server 比较字符是否相同
sqlserver
爱喝水的鱼丶4 天前
SAP-ABAP:SAP 内存管理详解:从架构到优化
开发语言·学习·架构·sap·abap·内存管理
赖龙4 天前
SQL Server 日志收缩实战:从空间告急到稳定运行
sqlserver
SAP_奥维奥科技5 天前
中国企业ERP选型白皮书(2026研究版)
云计算·sap·sap系统