SAP ABAP任意表数据查询+快速下载工具

背景:

项目上业务顾问有时候需要下载标准表大量的数据到Excel进行一些比对,但是标准SE16N,SE16的下载电子表格功能在遇到大批量数据的时候会非常慢,于是抽空写了个通用的查询下载工具,可以快速的下载数据。

2024.09.13更新:超大数量下载时分批多次下载还是有点麻烦,所以还是需要分批下载,超大文件下载时xlsx还是比较慢,索性直接禁用了,相关代码留着可以参考。

  • 分批下载需要使用游标查询,OPEN CURSOR,但是GUI_DOWNLOAD会隐式关闭游标,导致第二次游标查询引发Dump:DBIF_RSQL_INVALID_CURSOR,所以看起来只能借助服务器暂存一下,查询完之后分批下载。
  • 为了避免占用太多服务器空间,进行ZIP压缩后存储,下载后及时删除文件。
  • 现在可以保留动态选择输入的条件,不会需要再次重新输入。

工具界面:


功能介绍:

  • 单表查询:输入表名,执行后会进入动态条件选择界面,可自行添加选择条件。
  • 跨表关联查询:使用NativeSql语句查询你想要的数据,如果要查询SAP系统表数据,数据库连接名使用默认的‘DEFAULT’即可;如果要查询外部数据库数据,选择对应的DBCO连接名即可。(需要注意的是,查询SAP表数据时,需要添加MANDT条件限制客户端,否则将会查询所有客户端的数据)。
  • 下载功能:目前支持.txt/.csv/.xlsx三种格式的文件下载,.txt和.csv实际上都是文本格式,代码将数据转换为二进制形式下载,所以下载速度是最快的,.xlsx采用的OLE下载方式,下载速度相对来说会慢一些,但还是会标准的下载功能快一些的,但实际上下载为csv格式就可以正常用了,另存为xlsx格式就行,默认为自己电脑桌面路径,如果数据量过大导致资源瓶颈dump的话,也可以自行进行改造,使用游标查询分批将数据保存至服务器目录(AL11)再分批下载,本程序没有处理这种资源瓶颈问题,所以数据量过大时建议按条件进行查询下载。

 使用示例:

1.单表查询:

2.单表下载:

3.跨表查询:

4.跨表下载:


源码:

*&---------------------------------------------------------------------*
*& Report ZDOWNLOAD_TABLE_WITH_SEL
*&---------------------------------------------------------------------*
*& Author:DeveloprMrMeng
*& Usage :根据选择屏幕条件动态查询数据或者下载数据
*& Date  :2024.07.15
*&---------------------------------------------------------------------*
REPORT zdownload_table_with_sel.
TABLES:sscrfields.
TYPES:
  ty_excl TYPE rsexfcode,
  tt_excl TYPE STANDARD TABLE OF ty_excl.

DATA:
  go_dock        TYPE REF TO cl_gui_docking_container,
  go_text_editor TYPE REF TO cl_gui_textedit,
  gv_text_newtxt TYPE string,
  gv_text_oldtxt TYPE string,
  gt_texttab     TYPE soli_tab,
  gs_texttab     TYPE soli.

DATA:
  gv_sql              TYPE alk_string,
  gv_package_size     TYPE i VALUE 100000,
  gt_field_ranges_int TYPE rsds_trange,
  gv_file_name        TYPE string,
  gv_file_extension   TYPE string,
  gv_separator        TYPE string,
  gv_body_xstring     TYPE xstring,
  gv_zip_xstring      TYPE xstring,
  gt_zip_list         TYPE STANDARD TABLE OF string,
  gv_zip_name         TYPE string.

DATA:
  gt_fieldcat TYPE lvc_t_fcat,
  gs_fieldcat TYPE lvc_s_fcat.

FIELD-SYMBOLS:
  <gs_table> TYPE data,
  <gt_table> TYPE STANDARD TABLE.

SELECTION-SCREEN FUNCTION KEY 1.
SELECTION-SCREEN BEGIN OF BLOCK opt WITH FRAME TITLE t_opt.
PARAMETERS:
  p_singl RADIOBUTTON GROUP gp1 DEFAULT 'X' USER-COMMAND uc,
  p_multi RADIOBUTTON GROUP gp1.

PARAMETERS:
  p_down AS CHECKBOX USER-COMMAND down DEFAULT 'X'.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN POSITION 3.
SELECTION-SCREEN COMMENT 4(12) t_pksize FOR FIELD p_pksize MODIF ID dow.
PARAMETERS:p_pksize TYPE i DEFAULT 250000 MODIF ID dow.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK opt.

SELECTION-SCREEN BEGIN OF BLOCK single WITH FRAME TITLE t_sigl.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT 1(31) t_tab FOR FIELD p_tab MODIF ID sig.
PARAMETERS:p_tab TYPE dd02l-tabname MODIF ID sig.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK single.

SELECTION-SCREEN BEGIN OF BLOCK multiple WITH FRAME TITLE t_multi.
PARAMETERS:
  p_conn TYPE dbcon-con_name MODIF ID mul DEFAULT 'DEFAULT'.
SELECTION-SCREEN END OF BLOCK multiple.

SELECTION-SCREEN BEGIN OF BLOCK down WITH FRAME TITLE t_down.
PARAMETERS:
  p_file TYPE rlgrap-filename MODIF ID dow MEMORY ID file.
PARAMETERS:
  p_txt  RADIOBUTTON GROUP gp2 MODIF ID dow,
  p_csv  RADIOBUTTON GROUP gp2 DEFAULT 'X' MODIF ID dow,
  p_xlsx RADIOBUTTON GROUP gp2 MODIF ID dow.
SELECTION-SCREEN END OF BLOCK down.

INITIALIZATION.
* 初始化选择屏幕
  PERFORM frm_initial_screen.

AT SELECTION-SCREEN OUTPUT.
* 更新选择屏幕
  PERFORM frm_modify_screen.

AT SELECTION-SCREEN.
* 处理按钮响应
  PERFORM frm_ucomm_process.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
* 获取保存路径
  PERFORM frm_change_path CHANGING p_file.

START-OF-SELECTION.
* 处理执行按钮
  PERFORM frm_start_process.
*&---------------------------------------------------------------------*
*& Form frm_initial_screen
*&---------------------------------------------------------------------*
*& 初始化选择屏幕
*&---------------------------------------------------------------------*
FORM frm_initial_screen .
  DATA:
    ls_functxt      TYPE smp_dyntxt,
    lv_desktop_path TYPE string.

  t_opt    = '查询选项'(t01).
  t_down   = '下载选项'(t02).
  t_sigl   = '单表查询选择条件'(t03).
  t_multi  = '关联查询选择条件'(t04).
  t_tab    = '表名'(t05).
  t_pksize = 'Package Size'(t06).

  %_p_singl_%_app_%-text = '单表查询'(001).
  %_p_multi_%_app_%-text = 'NativeSql查询'(002).
  %_p_down_%_app_%-text  = '下载文件'(003).
  %_p_file_%_app_%-text  = '文件路径'(004).
  %_p_txt_%_app_%-text   = '.txt'(005).
  %_p_csv_%_app_%-text   = '.csv'(006).
  %_p_xlsx_%_app_%-text  = '.xlsx'(007).
  %_p_conn_%_app_%-text  = '数据库连接名'(008).

  ls_functxt-icon_id   = icon_fencing.
  ls_functxt-icon_text = '动态选择'(009).
  ls_functxt-quickinfo = '动态选择'(009).
  sscrfields-functxt_01 = ls_functxt.

  IF p_file IS INITIAL.
*   默认为当前用户桌面路径
    CALL METHOD cl_gui_frontend_services=>get_desktop_directory
      CHANGING
        desktop_directory    = lv_desktop_path
      EXCEPTIONS
        cntl_error           = 1
        error_no_gui         = 2
        not_supported_by_gui = 3
        OTHERS               = 4.

    CALL METHOD cl_gui_cfw=>update_view.

    IF sy-subrc = 0.
      CONDENSE lv_desktop_path NO-GAPS.
      p_file = lv_desktop_path.
    ENDIF.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_modify_screen
*&---------------------------------------------------------------------*
*& 更新选择屏幕
*&---------------------------------------------------------------------*
FORM frm_modify_screen .
  DATA:
    lt_excl TYPE STANDARD TABLE OF rsexfcode,
    ls_excl TYPE rsexfcode.

  FIELD-SYMBOLS:
    <lt_excel> TYPE tt_excl.

  LOOP AT SCREEN.
    CASE abap_on.
      WHEN p_singl.
        IF screen-group1 = 'MUL'.
          screen-active = 0.
        ENDIF.

        IF screen-name = 'P_TAB'.
          screen-required = 2.
        ENDIF.
      WHEN p_multi.
        IF screen-group1 = 'SIG'.
          screen-active = 0.
        ENDIF.
      WHEN OTHERS.
    ENDCASE.

    IF p_down = abap_off.
      IF screen-group1 = 'DOW'.
        screen-active = 0.
      ENDIF.
    ELSE.
      IF screen-name = 'P_FILE'.
        screen-required = 2.
      ENDIF.
    ENDIF.

    IF screen-name = 'P_XLSX'.
      screen-input = 0.
    ENDIF.
    MODIFY SCREEN.
  ENDLOOP.

  ASSIGN ('(RSDBRUNT)CURRENT_SCR-EXCL') TO <lt_excel>.

  IF p_singl = abap_on.
    DELETE <lt_excel> WHERE fcode = 'FC01'.

    IF go_dock IS NOT INITIAL.
      go_dock->free( ).
      CLEAR go_dock.
    ENDIF.

    IF go_text_editor IS NOT INITIAL.
      go_text_editor->free( ).
      CLEAR go_text_editor.
    ENDIF.
  ELSE.
    PERFORM insert_into_excl(rsdbrunt) USING 'FC01'.

*   创建SQL编辑器容器
    PERFORM frm_create_sql_editor.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_check_input
*&---------------------------------------------------------------------*
*& 检查输入
*&---------------------------------------------------------------------*
FORM frm_check_input .
  CASE abap_on.
    WHEN p_singl.
      IF p_tab IS INITIAL.
        SET CURSOR FIELD 'P_TAB'.
        MESSAGE e055(00).
      ENDIF.
    WHEN p_multi.

    WHEN OTHERS.
  ENDCASE.

  IF p_down = abap_on.
    IF p_file IS INITIAL.
      SET CURSOR FIELD 'P_FILE'.
      MESSAGE e055(00).
    ENDIF.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_ucomm_process
*&---------------------------------------------------------------------*
*& 处理按钮响应
*&---------------------------------------------------------------------*
FORM frm_ucomm_process .
  CASE sy-ucomm.
    WHEN 'ONLI'.
      PERFORM frm_check_input.
    WHEN 'FC01'.
      PERFORM frm_check_input.
      PERFORM frm_dynamic_search USING gt_field_ranges_int.
    WHEN OTHERS.
  ENDCASE.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_create_sql_editor
*&---------------------------------------------------------------------*
*& 创建SQL编辑器容器
*&---------------------------------------------------------------------*
FORM frm_create_sql_editor .
  CHECK go_dock IS INITIAL.

  CREATE OBJECT go_dock
    EXPORTING
      repid = sy-cprog
      dynnr = sy-dynnr
      ratio = 62
      side  = cl_gui_docking_container=>dock_at_bottom.

  CREATE OBJECT go_text_editor
    EXPORTING
      parent                     = go_dock
      wordwrap_mode              = '2'
      wordwrap_position          = '100'
      wordwrap_to_linebreak_mode = cl_gui_textedit=>true
    EXCEPTIONS
      error_cntl_create          = 1
      error_cntl_init            = 2
      error_cntl_link            = 3
      error_dp_create            = 4
      gui_type_not_supported     = 5.

  IMPORT gv_sql FROM MEMORY ID sy-repid.

  gv_text_newtxt = gv_sql.

  REFRESH gt_texttab.
  CALL FUNCTION 'SO_STRING_TO_TAB'
    EXPORTING
      content_str = gv_text_newtxt
    TABLES
      content_tab = gt_texttab.

  go_text_editor->set_text_as_r3table( EXPORTING table = gt_texttab ).

  CALL METHOD cl_gui_docking_container=>set_focus
    EXPORTING
      control = go_text_editor.

  CALL METHOD go_text_editor->set_readonly_mode
    EXPORTING
      readonly_mode          = 0
    EXCEPTIONS
      error_cntl_call_method = 1
      invalid_parameter      = 2
      OTHERS                 = 3.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_start_process
*&---------------------------------------------------------------------*
*& 处理执行按钮
*&---------------------------------------------------------------------*
FORM frm_start_process .
* 设置文件后缀
  PERFORM frm_set_file_extension.

  CASE abap_on.
    WHEN p_singl.
*     动态条件查询
      PERFORM frm_dynamic_search USING gt_field_ranges_int.
    WHEN p_multi.
*     从编辑器获取最新SQL
      PERFORM frm_get_sql.

*     调用ADBC方式获取数据
      PERFORM frm_call_adbc.
    WHEN OTHERS.
  ENDCASE.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_sql
*&---------------------------------------------------------------------*
*& 从编辑器获取最新SQL
*&---------------------------------------------------------------------*
FORM frm_get_sql .
  go_text_editor->get_text_as_r3table(
    IMPORTING
      table = gt_texttab
  ).

  CLEAR gv_sql.

  CALL FUNCTION 'SO_TAB_TO_STRING'
    IMPORTING
      content_str = gv_sql
    TABLES
      content_tab = gt_texttab.

  EXPORT gv_sql TO MEMORY ID sy-repid.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_call_adbc
*&---------------------------------------------------------------------*
*& 调用ADBC方式获取数据
*&---------------------------------------------------------------------*
FORM frm_call_adbc .
  DATA:
    lo_adbc_connect TYPE REF TO cl_sql_connection,
    lo_adbc_query   TYPE REF TO cl_sql_statement,
    lo_adbc_result  TYPE REF TO cl_sql_result_set,
    lo_metadata     TYPE REF TO data,
    ls_metadata     TYPE adbc_rs_metadata_descr,
    lt_metadata     TYPE adbc_rs_metadata_descr_tab.

  DATA:
    lo_sql_exception           TYPE REF TO cx_sql_exception,
    lo_parameter_invalid       TYPE REF TO cx_parameter_invalid,
    lo_parameter_invalid_range TYPE REF TO cx_parameter_invalid_range,
    lo_parameter_invalid_type  TYPE REF TO cx_parameter_invalid_type,
    lo_struct_creation         TYPE REF TO cx_sy_struct_creation,
    lo_table_creation          TYPE REF TO cx_sy_table_creation,
    lo_exception               TYPE REF TO data,
    lv_err_text                TYPE string,
    lv_rows_ret                TYPE i.

  DATA:
    lo_structdescr TYPE REF TO cl_abap_structdescr,
    lo_tabletype   TYPE REF TO cl_abap_tabledescr,
    lo_result_ref  TYPE REF TO data.

  DATA:
    lv_title_line   TYPE string,
    lv_body_line    TYPE string,
    lv_body_string  TYPE string,
    lv_body_xstring TYPE xstring.

  FIELD-SYMBOLS:
    <lv_field_value> TYPE any.

* 获取连接
  TRY .
      lo_adbc_connect = cl_sql_connection=>get_connection( con_name = p_conn ).
    CATCH cx_sql_exception INTO lo_sql_exception.
      lv_err_text = lo_sql_exception->get_text( ).
      WRITE lv_err_text.
      RETURN.
  ENDTRY.

* 创建连接对象
  lo_adbc_query = lo_adbc_connect->create_statement( ).

* 执行Sql
  TRY .
      lo_adbc_result = lo_adbc_query->execute_query( gv_sql ).
    CATCH cx_sql_exception INTO lo_sql_exception.
      lv_err_text = lo_sql_exception->get_text( ).
      WRITE lv_err_text.
      RETURN.
    CATCH cx_parameter_invalid INTO lo_parameter_invalid.
      lv_err_text = lo_parameter_invalid->get_text( ).
      WRITE lv_err_text.
      RETURN.
  ENDTRY.

* 获取元数据
  TRY .
      lt_metadata = lo_adbc_result->get_metadata( ).
    CATCH cx_sql_exception.
      lv_err_text = lo_sql_exception->get_text( ).
      WRITE lv_err_text.
      RETURN.
  ENDTRY.

* 获取元数据字段信息
  TRY .
      lo_metadata = lo_adbc_result->get_struct_ref( md_tab      = lt_metadata
                                                    string_only = abap_true
                                                    p_strict    = abap_false
                                                   ).
    CATCH cx_sy_struct_creation INTO lo_struct_creation.
      lv_err_text = lo_struct_creation->get_text( ).
      WRITE lv_err_text.
      RETURN.
    CATCH cx_parameter_invalid_range INTO lo_parameter_invalid_range.
      lv_err_text = lo_parameter_invalid_range->get_text( ).
      WRITE lv_err_text.
      RETURN.
  ENDTRY.

* 创建结构类型对象
  lo_structdescr ?= cl_abap_typedescr=>describe_by_data_ref( lo_metadata ).

* 创建表类型对象
  TRY .
      lo_tabletype = cl_abap_tabledescr=>create( p_line_type  = lo_structdescr
                                                 p_table_kind = cl_abap_tabledescr=>tablekind_std ).
    CATCH cx_sy_table_creation INTO lo_table_creation.
      lv_err_text = lo_table_creation->get_text( ).
      WRITE lv_err_text.
      RETURN.
  ENDTRY.

* 创建表对象引用
  CREATE DATA lo_result_ref TYPE HANDLE lo_tabletype.

* 传递sql结果至表对象引用
  TRY .
      lo_adbc_result->set_param_table( itab_ref = lo_result_ref ).
    CATCH cx_parameter_invalid INTO lo_parameter_invalid.
      lv_err_text = lo_parameter_invalid->get_text( ).
      WRITE lv_err_text.
      RETURN.
  ENDTRY.

  CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
    EXPORTING
*     PERCENTAGE       = 0
      text = '查询中...'(t07).

* 获取所有数据
  TRY .
      lo_adbc_result->next_package( EXPORTING upto = 0 ).
    CATCH cx_sql_exception INTO lo_sql_exception.
      lv_err_text = lo_sql_exception->get_text( ).
      WRITE lv_err_text.
      RETURN.
    CATCH cx_parameter_invalid_type INTO lo_parameter_invalid_type.
      lv_err_text = lo_parameter_invalid_type->get_text( ).
      WRITE lv_err_text.
      RETURN.
  ENDTRY.

* 关闭连接
  lo_adbc_result->close( ).

* 赋值到动态内表
  ASSIGN lo_result_ref->* TO <gt_table>.

  IF <gt_table> IS INITIAL.
    MESSAGE '不包含符合条件数据!'(m01) TYPE 'S' DISPLAY LIKE 'E'.
    LEAVE LIST-PROCESSING.
  ENDIF.

* 设置字段控制
  LOOP AT lt_metadata INTO ls_metadata.
    gs_fieldcat-fieldname = ls_metadata-column_name.
    TRANSLATE gs_fieldcat-fieldname TO UPPER CASE.
    gs_fieldcat-scrtext_l = ls_metadata-column_name.
    APPEND gs_fieldcat TO gt_fieldcat.
    CLEAR gs_fieldcat.
  ENDLOOP.

  IF p_down = abap_on.
    IF p_xlsx <> abap_on.
*     标题行拼接换行符
      LOOP AT gt_fieldcat INTO gs_fieldcat.
        lv_title_line = lv_title_line && gv_separator && gs_fieldcat-scrtext_l.
      ENDLOOP.

      SHIFT lv_title_line.

*     标题行拼接换行符
      lv_body_string = lv_title_line && cl_abap_char_utilities=>cr_lf.

      LOOP AT <gt_table> ASSIGNING <gs_table>.
        DO.
          ASSIGN COMPONENT sy-index OF STRUCTURE <gs_table> TO <lv_field_value>.
          IF sy-subrc <> 0.
            EXIT.
          ENDIF.

*         内容行拼接分隔符
          lv_body_line = lv_body_line && gv_separator && <lv_field_value>.
        ENDDO.

        SHIFT lv_body_line.

*       内容行拼接换行符
        lv_body_line  = lv_body_line && cl_abap_char_utilities=>cr_lf.

*       拼接内容行
        lv_body_string = lv_body_string && lv_body_line.

        CLEAR lv_body_line.
      ENDLOOP.

      CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
        EXPORTING
          text     = lv_body_string
          mimetype = 'UTF-8'
        IMPORTING
          buffer   = gv_body_xstring.

      CONCATENATE cl_abap_char_utilities=>byte_order_mark_utf8
                  gv_body_xstring
             INTO gv_body_xstring IN BYTE MODE.
    ENDIF.

*   下载文件
    PERFORM frm_download_file.
  ELSE.
*   ALV展示
    PERFORM frm_display_alv.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_change_path
*&---------------------------------------------------------------------*
*& 获取保存路径
*&---------------------------------------------------------------------*
*&      <-- CV_FILE_PATH   文件路径
*&---------------------------------------------------------------------*
FORM frm_change_path  CHANGING cv_file_path.
  DATA lv_path TYPE string.

  CALL METHOD cl_gui_frontend_services=>directory_browse
    CHANGING
      selected_folder      = lv_path
    EXCEPTIONS
      cntl_error           = 1
      error_no_gui         = 2
      not_supported_by_gui = 3
      OTHERS               = 4.

  cv_file_path = lv_path.
ENDFORM.
*&---------------------------------------------------------------------*
*&      Form  FRM_DISPLAY_ALV
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM frm_display_alv.
  DATA:
    ls_layout       TYPE lvc_s_layo,
    lt_excluding    TYPE slis_t_extab,
    lt_event        TYPE slis_t_event,
    ls_event        TYPE slis_alv_event,
    lt_event_exit   TYPE slis_t_event_exit,
    ls_event_exit   TYPE slis_event_exit,
    ls_ddval        TYPE lvc_s_drop,
    ls_grid_setting TYPE lvc_s_glay.

  FIELD-SYMBOLS:
    <ls_fieldcat> TYPE lvc_s_fcat.

* 设置布局控制
  ls_layout-zebra      = 'X'.                     "颜色间隔
  ls_layout-sel_mode   = 'D'.                     "选择模式
  ls_layout-cwidth_opt = 'X'.                     "列宽自适应
* 展示ALV
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
    EXPORTING
      i_callback_program = sy-repid
      is_layout_lvc      = ls_layout
      it_fieldcat_lvc    = gt_fieldcat
      it_excluding       = lt_excluding
      i_grid_settings    = ls_grid_setting
*     IT_SORT_LVC        =
      i_save             = 'A'
*     IS_VARIANT         =
      it_events          = lt_event
      it_event_exit      = lt_event_exit
    TABLES
      t_outtab           = <gt_table>
    EXCEPTIONS
      program_error      = 1
      OTHERS             = 2.
  IF sy-subrc <> 0.
*   Implement suitable error handling here
  ENDIF.
ENDFORM. "FRM_DISPLAY_ALV
*&---------------------------------------------------------------------*
*& Form frm_download_file
*&---------------------------------------------------------------------*
*& 下载文件
*&---------------------------------------------------------------------*
FORM frm_download_file .
  CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
    EXPORTING
      text = '下载中...'(t06).

  CASE abap_on.
    WHEN p_txt OR p_csv.
*     以txt格式下载文件
      PERFORM frm_download_txt.
    WHEN p_xlsx.
*     以xlsx格式下载文件
      PERFORM frm_download_xlsx.
    WHEN OTHERS.
  ENDCASE.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_DYNAMIC_SEARCH
*&---------------------------------------------------------------------*
*& 动态条件查询
*&---------------------------------------------------------------------*
*& -->  UT_FIELD_RANGES_INT        选择条件SELECT-OPTION
*&---------------------------------------------------------------------*
FORM frm_dynamic_search  USING ut_field_ranges_int TYPE rsds_trange.
  DATA:
    lv_selection_id     TYPE rsdynsel-selid,
    lt_tables_tab       TYPE STANDARD TABLE OF rsdstabs,
    ls_tables_tab       TYPE rsdstabs,
    lt_fields_tab       TYPE STANDARD TABLE OF rsdsfields,
    ls_fields_tab       TYPE rsdsfields,
    lt_fcode_tab        TYPE STANDARD TABLE OF rsdsfcode,
    ls_fcode_tab        TYPE rsdsfcode,
    ls_pfkey            TYPE rsdspfkey,
    lt_where_clauses    TYPE rsds_twhere,
    ls_where_clauses    TYPE rsds_where,
    ls_where_tab        TYPE rsdswhere,
    ls_where_cond       TYPE string,
    ls_field_ranges_int TYPE rsds_range,
    ls_range_t          TYPE rsds_frange.

  DATA:
    lt_dfies_tab TYPE STANDARD TABLE OF dfies,
    ls_dfies_tab TYPE dfies.

  CALL FUNCTION 'DDIF_NAMETAB_GET'
    EXPORTING
      tabname   = p_tab
    TABLES
      dfies_tab = lt_dfies_tab
    EXCEPTIONS
      not_found = 1
      OTHERS    = 2.

  IF sy-subrc <> 0.
*   Implement suitable error handling here
    MESSAGE ID sy-msgid
          TYPE sy-msgty
        NUMBER sy-msgno
          WITH sy-msgv1
               sy-msgv2
               sy-msgv3
               sy-msgv4.
  ENDIF.

  LOOP AT lt_dfies_tab INTO ls_dfies_tab WHERE keyflag = 'X' AND fieldname <> 'MANDT'.
    ls_fields_tab-tablename = ls_dfies_tab-tabname.
    ls_fields_tab-fieldname = ls_dfies_tab-fieldname.
    APPEND ls_fields_tab TO lt_fields_tab.
  ENDLOOP.

* 将上次查询条件追加进来
  LOOP AT ut_field_ranges_int INTO ls_field_ranges_int WHERE tablename = p_tab.
    LOOP AT ls_field_ranges_int-frange_t INTO ls_range_t.
      READ TABLE lt_fields_tab TRANSPORTING NO FIELDS
        WITH KEY tablename = ls_field_ranges_int-tablename
                 fieldname = ls_range_t-fieldname.
      IF sy-subrc <> 0.
        ls_fields_tab-tablename = ls_field_ranges_int-tablename.
        ls_fields_tab-fieldname = ls_range_t-fieldname.
        APPEND ls_fields_tab TO lt_fields_tab.
      ENDIF.
    ENDLOOP.
  ENDLOOP.

  ls_tables_tab-prim_tab = p_tab.
  APPEND ls_tables_tab TO lt_tables_tab.

  CALL FUNCTION 'FREE_SELECTIONS_INIT'
    EXPORTING
      kind                     = 'T'
      field_ranges_int         = ut_field_ranges_int
    IMPORTING
      selection_id             = lv_selection_id
    TABLES
      tables_tab               = lt_tables_tab
      fields_tab               = lt_fields_tab
    EXCEPTIONS
      fields_incomplete        = 1
      fields_no_join           = 2
      field_not_found          = 3
      no_tables                = 4
      table_not_found          = 5
      expression_not_supported = 6
      incorrect_expression     = 7
      illegal_kind             = 8
      area_not_found           = 9
      inconsistent_area        = 10
      kind_f_no_fields_left    = 11
      kind_f_no_fields         = 12
      too_many_fields          = 13
      dup_field                = 14
      field_no_type            = 15
      field_ill_type           = 16
      dup_event_field          = 17
      node_not_in_ldb          = 18
      area_no_field            = 19
      OTHERS                   = 20.

  IF sy-subrc EQ 0.
    ls_pfkey-pfkey   = sy-pfkey.
    ls_pfkey-program = sy-repid.

    CALL FUNCTION 'FREE_SELECTIONS_DIALOG'
      EXPORTING
        selection_id    = lv_selection_id
        title           = sy-title
        frame_text      = TEXT-001
        status          = 1
        no_intervals    = ''
        as_window       = ''
        as_subscreen    = ''
        tree_visible    = 'X'                                           "是否显示条件Tree
      IMPORTING
        where_clauses   = lt_where_clauses                              "返回选择条件
      TABLES
        fields_tab      = lt_fields_tab                                 "选择画面中选中字段
        fcode_tab       = lt_fcode_tab
      EXCEPTIONS
        internal_error  = 1
        no_action       = 2
        selid_not_found = 3
        illegal_status  = 4
        OTHERS          = 5.
    IF sy-subrc EQ 0.
      READ TABLE lt_where_clauses INTO ls_where_clauses INDEX 1.

      LOOP AT ls_where_clauses-where_tab INTO ls_where_tab.
        ls_where_cond = ls_where_cond && ` ` && ls_where_tab-line.
      ENDLOOP.

*     查询取数:下载or展示
      PERFORM frm_get_data USING p_tab ls_where_cond.

      CALL FUNCTION 'FREE_SELECTIONS_WHERE_2_RANGE'
        EXPORTING
          where_clauses            = lt_where_clauses
        IMPORTING
          field_ranges             = gt_field_ranges_int
        EXCEPTIONS
          expression_not_supported = 1
          incorrect_expression     = 2
          OTHERS                   = 3.

*     动态查询
      PERFORM frm_dynamic_search USING gt_field_ranges_int.
    ENDIF.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_build_tab
*&---------------------------------------------------------------------*
*& 构建动态内表
*&---------------------------------------------------------------------*
FORM frm_build_tab .
  DATA:
    lo_tab_ref  TYPE REF TO data,
    lo_line_ref TYPE REF TO data.
  CREATE DATA lo_tab_ref TYPE STANDARD TABLE OF (p_tab).
  CREATE DATA lo_line_ref TYPE (p_tab).
  ASSIGN lo_tab_ref->* TO <gt_table>.
  ASSIGN lo_line_ref->* TO <gs_table>.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_fieldcat
*&---------------------------------------------------------------------*
*& 获取Fieldcat
*&---------------------------------------------------------------------*
FORM frm_get_fieldcat .
  CLEAR gt_fieldcat.
* 设置字段控制
  CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
    EXPORTING
      i_structure_name       = p_tab
    CHANGING
      ct_fieldcat            = gt_fieldcat
    EXCEPTIONS
      inconsistent_interface = 1
      program_error          = 2
      OTHERS                 = 3.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_download_txt
*&---------------------------------------------------------------------*
*& 以txt格式下载文件
*&---------------------------------------------------------------------*
FORM frm_download_txt .
  DATA:
    lv_file_xstring TYPE xstring,
    lv_len          TYPE i,
    lt_data_tab     TYPE STANDARD TABLE OF w3mime,
    lv_filename     TYPE string.

  LOOP AT gt_zip_list INTO gv_zip_name.
    OPEN DATASET gv_zip_name FOR INPUT IN BINARY MODE.
    IF sy-subrc = 0.
      READ DATASET gv_zip_name INTO lv_file_xstring LENGTH lv_len.
      CLOSE DATASET gv_zip_name.

      lv_filename = p_file && '/' && gv_zip_name.

      CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
        EXPORTING
          buffer        = lv_file_xstring
        IMPORTING
          output_length = lv_len
        TABLES
          binary_tab    = lt_data_tab.

      CALL FUNCTION 'GUI_DOWNLOAD'
        EXPORTING
          bin_filesize            = lv_len
          filename                = lv_filename
          filetype                = 'BIN'
*         WRITE_FIELD_SEPARATOR   = ' '
          confirm_overwrite       = 'X'
          codepage                = '8404'
*         REPLACEMENT             = '#'
*         WRITE_BOM               = ' '
        TABLES
          data_tab                = lt_data_tab
        EXCEPTIONS
          file_write_error        = 1
          no_batch                = 2
          gui_refuse_filetransfer = 3
          invalid_type            = 4
          no_authority            = 5
          unknown_error           = 6
          header_not_allowed      = 7
          separator_not_allowed   = 8
          filesize_not_allowed    = 9
          header_too_long         = 10
          dp_error_create         = 11
          dp_error_send           = 12
          dp_error_write          = 13
          unknown_dp_error        = 14
          access_denied           = 15
          dp_out_of_memory        = 16
          disk_full               = 17
          dp_timeout              = 18
          file_not_found          = 19
          dataprovider_exception  = 20
          control_flush_error     = 21
          OTHERS                  = 22.

      IF sy-subrc <> 0.
        MESSAGE ID sy-msgid
              TYPE sy-msgty
            NUMBER sy-msgno
              WITH sy-msgv1
                   sy-msgv2
                   sy-msgv3
                   sy-msgv4.
      ELSE.
        MESSAGE lv_filename TYPE 'S'.
      ENDIF.

      DELETE DATASET gv_zip_name.
    ENDIF.

    CLEAR:
      lv_file_xstring,
      lv_len,
      lt_data_tab.
  ENDLOOP.

  CLEAR gt_zip_list.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_download_xlsx
*&---------------------------------------------------------------------*
*& 以xlsx格式下载文件
*&---------------------------------------------------------------------*
FORM frm_download_xlsx .
* OLE使用相关参数定义
  DATA:
    myexcel      TYPE ole2_object,
    mysheet      TYPE ole2_object,
    mysheetname  TYPE ole2_object,
    mycell       TYPE ole2_object,
    mycell_begin TYPE ole2_object,
    mycell_end   TYPE ole2_object,
    myworkbook   TYPE ole2_object,
    myrange      TYPE ole2_object,
    myrange_all  TYPE ole2_object,
    myborders    TYPE ole2_object,
    myinterior   TYPE ole2_object.

  DATA:
    lv_filename    TYPE string,
    lv_title_line1 TYPE char8000_d,
    lv_title_line2 TYPE char8000_d,
    lv_body_line   TYPE char8000_d,
    lt_body        TYPE STANDARD TABLE OF char8000_d,
    lv_body_string TYPE string,
    lv_total_col   TYPE i,
    lv_total_row   TYPE i,
    lv_rc          TYPE i,
    lv_group_size  TYPE i,
    lv_count       TYPE i,
    lv_row_index   TYPE i,
    lv_past_times  TYPE i.

  CONSTANTS:
    lc_max_siz TYPE i VALUE 100000.

  FIELD-SYMBOLS:
    <lv_field_value> TYPE any.

  lv_filename = p_file && '\' && gv_file_name.

  lv_total_col = lines( gt_fieldcat ).

* 创建excel对象
  CREATE OBJECT myexcel 'excel.application'.

* 设置后台执行  0后台 1前台
  SET PROPERTY OF myexcel 'visible' = 0.

* 创建工作簿对象
  CALL METHOD OF
    myexcel
      'Workbooks' = myworkbook.

* 添加空白工作簿
  CALL METHOD OF
    myworkbook
    'Add'.

  FREE OBJECT myworkbook.

* 创建Sheet
  CALL METHOD OF
      myexcel
      'Worksheets' = mysheet
    EXPORTING
      #1           = 1.

* 激活当前Sheet
  CALL METHOD OF
    mysheet
    'Activate'.

  LOOP AT gt_fieldcat INTO gs_fieldcat.
*   标题行:描述
    lv_title_line1 = lv_title_line1 && gv_separator && gs_fieldcat-scrtext_l.
*   标题行:字段名
    lv_title_line2 = lv_title_line2 && gv_separator && gs_fieldcat-fieldname.
  ENDLOOP.

  SHIFT lv_title_line1.
  APPEND lv_title_line1 TO lt_body.

  ADD 1 TO lv_group_size.
  ADD 1 TO lv_count.

  SHIFT lv_title_line2.
  APPEND lv_title_line2 TO lt_body.

  ADD 1 TO lv_group_size.
  ADD 1 TO lv_count.

  lv_total_row = lines( <gt_table> ) + 2.

  LOOP AT <gt_table> ASSIGNING <gs_table>.
    DO.
      ASSIGN COMPONENT sy-index OF STRUCTURE <gs_table> TO <lv_field_value>.
      IF sy-subrc <> 0.
        EXIT.
      ENDIF.

*     内容行拼接分隔符
      lv_body_line = lv_body_line && gv_separator && <lv_field_value>.
    ENDDO.

    SHIFT lv_body_line.
    APPEND lv_body_line TO lt_body.

    CLEAR lv_body_line.

    ADD 1 TO lv_group_size.
    ADD 1 TO lv_count.

*   按照指定数据分组大小依次分组粘贴
    IF lv_group_size >= lc_max_siz OR lv_count = lv_total_row.
*     将内容复制进粘贴板
      CALL METHOD cl_gui_frontend_services=>clipboard_export
        IMPORTING
          data                 = lt_body
        CHANGING
          rc                   = lv_rc
        EXCEPTIONS
          cntl_error           = 1
          error_no_gui         = 2
          not_supported_by_gui = 3
          OTHERS               = 4.

      ADD 1 TO lv_past_times.
      lv_row_index = ( lv_past_times * lc_max_siz ) - lc_max_siz + 1.

*     选中单元格
      CALL METHOD OF
          mysheet
          'Cells' = mycell
        EXPORTING
          #1      = lv_row_index
          #2      = 1.

*     选中单元格
      CALL METHOD OF
        mycell
        'Select'.

*     内容粘贴
      CALL METHOD OF
        mycell
        'PasteSpecial'.

      CLEAR:
        lt_body,
        lv_group_size.
    ENDIF.
  ENDLOOP.

* 全选
  CALL METHOD OF
    mysheet
      'Columns' = myrange_all.

* 自动适配列宽
  CALL METHOD OF
    myrange_all
    'AutoFit'.

* 范围起始单元格
  CALL METHOD OF
      mysheet
      'Cells' = mycell_begin
    EXPORTING
      #1      = 1
      #2      = 1.

* 范围截止单元格
  CALL METHOD OF
      mysheet
      'Cells' = mycell_end
    EXPORTING
      #1      = 2
      #2      = lv_total_col.

* 获取范围对象
  CALL METHOD OF
      mysheet
      'Range' = myrange
    EXPORTING
      #1      = mycell_begin
      #2      = mycell_end.

* 选中范围
  CALL METHOD OF
    myrange
    'Select'.

* 变更颜色
  GET PROPERTY OF myrange 'Interior' = myinterior.
  SET PROPERTY OF myinterior 'ColorIndex' = 15.

* 设置框线
  GET PROPERTY OF myrange 'Borders' = myborders.
  SET PROPERTY OF myborders 'Weight' = 2.

* 定位到第三行第一列
  CALL METHOD OF
      mysheet
      'Cells' = mycell
    EXPORTING
      #1      = 3
      #2      = 1.

* 选中单元格
  CALL METHOD OF
    mycell
    'Select'.

* 切换至首页
  CALL METHOD OF
      myexcel
      'Worksheets' = mysheet
    EXPORTING
      #1           = 1.

* 激活当前Sheet
  CALL METHOD OF
    mysheet
    'Activate'.

  FREE OBJECT mysheet.

* 获取活动的工作簿
  GET PROPERTY OF myexcel 'ActiveWorkbook' = myworkbook.

* 另存为
  CALL METHOD OF
    myworkbook
    'SaveAs'
    EXPORTING
      #1 = lv_filename                                                  "保存路径
      #2 = 51.                                                          "XlFileFormat:默认为*.xls  51为*.xlsx

* 保存并关闭
  CALL METHOD OF
    myworkbook
    'Close'
    EXPORTING
      #1 = 'True'.                                                      "覆盖时弹窗确认

  FREE OBJECT:
    myworkbook.

* 退出EXCEL
  CALL METHOD OF
    myexcel
    'Quit'.

* 释放对象
  FREE OBJECT mycell_begin.
  FREE OBJECT mycell_end.
  FREE OBJECT mycell.
  FREE OBJECT myrange.
  FREE OBJECT myinterior.
  FREE OBJECT myborders.
  FREE OBJECT mysheet.
  FREE OBJECT myexcel.

* 下载成功!
  MESSAGE lv_filename TYPE 'S'.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_set_file_extension
*&---------------------------------------------------------------------*
*& 设置文件后缀
*&---------------------------------------------------------------------*
FORM frm_set_file_extension .
  IF p_down = abap_on.
    CASE abap_on.
      WHEN p_txt.
        gv_file_extension = '.txt'.
        gv_separator      = cl_abap_char_utilities=>horizontal_tab.
      WHEN p_csv.
        gv_file_extension = '.csv'.
        gv_separator      = ','.
      WHEN p_xlsx.
        gv_file_extension = '.xlsx'.
        gv_separator      = cl_abap_char_utilities=>horizontal_tab.
      WHEN OTHERS.
    ENDCASE.
  ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_data
*&---------------------------------------------------------------------*
*& 查询取数
*&---------------------------------------------------------------------*
*& -->  UV_TAB               数据库表名
*& -->  UV_WHERE_COND        Where条件
*&---------------------------------------------------------------------*
FORM frm_get_data USING uv_tab        TYPE dd02l-tabname
                        uv_where_cond TYPE string.
  DATA:
    lv_title_line   TYPE string,
    lv_body_line    TYPE string,
    lv_body_string  TYPE string,
    lv_body_xstring TYPE xstring,
    lv_cursor       TYPE cursor,
    lo_zip          TYPE REF TO cl_abap_zip.

  FIELD-SYMBOLS:
    <lv_field_value> TYPE any.

  CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
    EXPORTING
      text = '查询中...'(t07).

* 构建全局动态内表
  PERFORM frm_build_tab.

* 获取Fieldcat
  PERFORM frm_get_fieldcat.

  IF p_down = abap_on.
*   标题行拼接换行符
    LOOP AT gt_fieldcat INTO gs_fieldcat.
      lv_title_line = lv_title_line && gv_separator && gs_fieldcat-scrtext_l.
    ENDLOOP.

    SHIFT lv_title_line.

    OPEN CURSOR WITH HOLD lv_cursor FOR SELECT * FROM (uv_tab) WHERE (uv_where_cond).

    DO.
      FETCH NEXT CURSOR lv_cursor INTO TABLE <gt_table> PACKAGE SIZE p_pksize.
      IF sy-subrc <> 0.
        EXIT.
      ENDIF.

      gv_file_name = uv_tab && '_' && sy-datlo && sy-timlo && '_' && sy-index && gv_file_extension.
      gv_zip_name  = uv_tab && '_' && sy-datlo && sy-timlo && '_' && sy-index && '.ZIP'.

      OPEN DATASET gv_zip_name FOR OUTPUT IN BINARY MODE.

*     标题行拼接换行符
      lv_body_string = lv_title_line && cl_abap_char_utilities=>cr_lf.

      LOOP AT <gt_table> ASSIGNING <gs_table>.
        DO.
          ASSIGN COMPONENT sy-index OF STRUCTURE <gs_table> TO <lv_field_value>.
          IF sy-subrc <> 0.
            EXIT.
          ENDIF.

*         内容行拼接分隔符
          lv_body_line = lv_body_line && gv_separator && <lv_field_value>.
        ENDDO.

        SHIFT lv_body_line.

*       内容行拼接换行符
        lv_body_line  = lv_body_line && cl_abap_char_utilities=>cr_lf.

*       拼接内容行
        lv_body_string = lv_body_string && lv_body_line.

        CLEAR lv_body_line.
      ENDLOOP.

      CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
        EXPORTING
          text     = lv_body_string
          mimetype = 'UTF-8'
        IMPORTING
          buffer   = gv_body_xstring.

      CONCATENATE cl_abap_char_utilities=>byte_order_mark_utf8
                  gv_body_xstring
             INTO gv_body_xstring IN BYTE MODE.

      CREATE OBJECT lo_zip.

      lo_zip->add( name    = gv_file_name
                   content = gv_body_xstring ).

      gv_zip_xstring = lo_zip->save( ).

      TRANSFER gv_zip_xstring TO gv_zip_name.
      CLOSE DATASET gv_zip_name.
      APPEND gv_zip_name TO gt_zip_list.

      CLEAR:
        gv_body_xstring,
        gv_zip_name,
        gv_file_name,
        lv_body_line.

      FREE:
        lo_zip.
    ENDDO.

    CLOSE CURSOR lv_cursor.

*   下载文件
    PERFORM frm_download_file.
  ELSE.
    SELECT *
       INTO TABLE <gt_table>
       FROM (uv_tab)
      WHERE (uv_where_cond).

    IF <gt_table> IS INITIAL.
      MESSAGE '不包含符合条件数据!'(m01) TYPE 'S' DISPLAY LIKE 'E'.
      LEAVE LIST-PROCESSING.
    ENDIF.

*   ALV输出
    PERFORM frm_display_alv.
  ENDIF.
ENDFORM.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeveloperMrMeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值