1 主要代码讲解
程序总体逻辑:根据配置表构造活动sql的select语句,讲取到的数据存储到活动内表,然后对活动内表进行处理,导出数据到本地,或者sap服务器。
1.1活动sql
sql语句由四部分组成 select ... from ... where... into ... ,sap可以使用字符串代替这四部分,本程序运用此特性将维护表数据构造成活动sql取值
1.2活动内表
类方法cl_alv_table_create=>create_dynamic_table 传入参考的字段清单即可构造成动态内表,将结果构造成与上文的sql结构一致,即可不浪费内存,不浪费算力存储数据
1.3二进制数据流数据导出
将数据按照格式构造成二进制数据流的方式,然后导出到sap服务器能访问的地址
1.3.1构造二进制数据流的CSV文件
二进制数据流是由一整串的字符串,在字符串中逗号代表csv文件的下一个单元格,调用方法 CL_ABAP_CHAR_UTILITIES=>CR_LF(1) 拼入字符串中代表csv文件的换行,所以我们只要先构造表头,从表DD03M 取表字段的描述作为表头,然后循环上文取到的内表数据,用逗号连接字段,循环完成后凭借换行符,最后就完成了文件的构造了。
1.3.2为数据转码
上文得到的数据目前是未转码的数据,需要将数据转换为二进制数据,服务器才能识别,
CALL FUNCTION 'SCMS_STRING_TO_XSTRING 为数据转码。
1.3.3将文件写入服务器
1.语句OPEN DATASET lv_file FOR OUTPUT IN BINARY MODE . 可以打开文件位置路径,路径参数为lv_file
2.将上文转码后的二进制文件写入打开的服务器地址TRANSFER ld_xstring TO lv_file. 将文件ld_xstring 写入刚刚打开的位置 lv_file
3.CLOSE DATASET lv_file. 写入完成后关闭连接,这一步必须要有,不然服务器一直会占用着这个文件,即便,数据已经写入完成了也不能再操作这个文件。
1.4导出至服务器的优缺点
导出至服务器构造的是csv格式的excel文件,该格式由一个字符串组成,空格代表下一个单元格 ,调用方法 cl_abap_char_utilities=>cr_lf(1) 代表换行,由于是服务器处理数据,且活动内表没有浪费多余的算力,数据构造速度快,但是快带来的缺点是excel的单元格格式都是默认的,无法做修改。
1.5导出至本地
导出至本地调用的是函数 GUI_DOWNLOAD ,将数据表传入参数data_tab。
然后将标题数据传入参数fieldnames。然后将文件地址传入参数filename。这样就能将文件导出至指定目录了。
1.6导出至本地的优缺点
导出至本地优点就是操作简单,也能灵活的调整单元格格式,速度也不会很慢,缺点就是在导出程序是不能使用后台导出,只能一直占用本机的资源。在数据量非常巨大的时候时间也需要很久。
2 配置表
2.1配置表结构
2.2参考配置表数据如下
3选择屏幕文本
4.导出至服务器的配置
项目上要和外围系统做接口,把传过来的文件写入到sap的文件服务器或者存入表中,让外围系统过来存取,但是为了减少SAP应用服务器的负担,需要一台独立的文件服务器共享目录到SAP应用服务器,实现往SAP应用服务器上写文件,实际上是写在了这台独立的文件服务器上。
4.1让basis将文件服务器与sap服务器做连接
我们需要让Basis把文件服务器和SAP应用服务器做NFS,开放给SAP相应权限。然后在al11新增文件目录,这个目录就是上文我们需要用到的目录,当然如果没有文件服务器也可以使用sap服务器作为导出地址,al11目录下的所有地址都可以作为文件导出地址
4.2查看及下载文件
导出完成后如果想查看文件可以进事务代码AL11,双击打开导入的文件夹,就能看到之前导出的文件的清单了。下图红框框中的按钮就是导出按钮。如果不想在sap操作文件也可以直接进服务器的该目录操作该文件
利用灵活sql取配置表数据构造动态内表导出至本地及服务器,代码如下
*&---------------------------------------------------------------------*
*& Report ZFIR252
*&---------------------------------------------------------------------*
*& author 李强 Qunending 2022.02.16
*&---------------------------------------------------------------------*
REPORT zexport_table.
TABLES:sscrfields,ztexport.
DATA:ok_code LIKE sy-ucomm.
DATA:stbl TYPE lvc_s_stbl.
DATA: gt_field TYPE lvc_t_fcat.
DATA: gt_fieldISP TYPE lvc_t_fcat.
DATA: gt_field2 TYPE lvc_t_fcat.
DATA: gs_field TYPE lvc_s_fcat.
DATA: GS_LAYOUT TYPE LVC_S_LAYO.
DATA: GS_VARIANT TYPE DISVARIANT.
FIELD-SYMBOLS:<itab> TYPE STANDARD TABLE,
<wa>,<ft> TYPE lvc_t_styl,
<fv>,<f1>,<f2>,<f3>.
FIELD-SYMBOLS:<itab2> TYPE STANDARD TABLE,
<wa2>,<ft2> TYPE lvc_t_styl,
<fv2>,<f12>,<f22>,<f32>.
DATA: dy_table TYPE REF TO data, ""取值的动态内表
dy_line TYPE REF TO data.
DATA: dy_table2 TYPE REF TO data, ""输出的动态内表,每个字段暂定char128,
dy_line2 TYPE REF TO data.
FIELD-SYMBOLS: <dyn_table> TYPE table,
<gt_table> TYPE table,
<dyn_wa> TYPE any.
FIELD-SYMBOLS : <fs_tab> TYPE ANY TABLE .
DATA gv_selea TYPE string . ""select 哪些字段
DATA gv_from TYPE string . ""FROM 哪个表怎么连表
DATA gv_where TYPE string . ""WHERE 哪些条件
DATA gt_exp TYPE TABLE OF ztexport .
SELECTION-SCREEN BEGIN OF BLOCK a1 WITH FRAME TITLE TEXT-001.
PARAMETERS : p_versi TYPE zeversi .
PARAMETERS : P_DISP RADIOBUTTON GROUP r2 DEFAULT 'X' USER-COMMAND uc .
PARAMETERS : P_EXPO RADIOBUTTON GROUP r2 .
PARAMETERS : p_file LIKE rlgrap-filename DEFAULT '/gacmotor/sap/' MODIF ID M1. "/gacmotor/sap "AL11中的文件目录都可以导出,需要与basis联系询问具体地址
PARAMETERS : p_numb TYPE sy-index DEFAULT '1000000' MODIF ID M1.
PARAMETERS : p_serv RADIOBUTTON GROUP r1 DEFAULT 'X' MODIF ID M1.
PARAMETERS : p_loca RADIOBUTTON GROUP r1 MODIF ID M1.
SELECTION-SCREEN END OF BLOCK a1.
"SELECTION-SCREEN FUNCTION KEY 1. "
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
PERFORM frm_f4_p_file .
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_versi.
PERFORM frm_f4_p_versi .
*************************************************************************
** INITIALIZATION
*************************************************************************
"该事件在屏幕未显示之前执行,对程序设置值及屏幕元素进行初始化赋值。
INITIALIZATION.
stbl-row = 'X'.
stbl-col = 'X'.
sscrfields-functxt_01 = '维护审计导出字段配置表'.
"假必输
LOOP AT SCREEN.
IF screen-name = 'P_VERSI'.
screen-required = '2'.
ENDIF.
MODIFY SCREEN.
ENDLOOP.
*************************************************************************
** AT SELECTION SCREEN
*************************************************************************
AT SELECTION-SCREEN.
CASE sscrfields-ucomm. "处理按钮命令
WHEN'FC01'.
CALL FUNCTION 'VIEW_MAINTENANCE_CALL'
EXPORTING
action = 'U'
view_name = 'ZTEXPORT'.
WHEN OTHERS.
ENDCASE.
*************************************************************************
** AT SELECTION SCREEN OUTPUT
*************************************************************************
AT SELECTION-SCREEN OUTPUT.
LOOP AT SCREEN.
CASE screen-group1.
WHEN 'M1' .
IF P_DISP = 'X'.
screen-active = '0'.
ELSE.
screen-active = '1'.
ENDIF.
ENDCASE .
IF screen-name = 'P_VERSI'.
screen-required = '2'.
ENDIF.
MODIFY SCREEN.
ENDLOOP.
*************************************************************************
* EVENT START OF SELECTION
*************************************************************************
START-OF-SELECTION.
PERFORM frm_check_exp_data .
PERFORM bulid_select .
IF P_EXPO = 'X'.
PERFORM export_data_to_ser .
PERFORM export_data_to_loc .
ELSEIF P_DISP = 'X' .
PERFORM FRM_DISPLAY_ALV .
ENDIF.
*************************************************************************
**EVENT END-OF SELECTION
*************************************************************************
END-OF-SELECTION.
FORM frm_check_exp_data.
"取配置表数据
SELECT * FROM ztexport INTO TABLE @gt_exp WHERE versi = @p_versi .
IF gt_exp IS INITIAL.
MESSAGE '请先维护表ZTEXPORT' TYPE 'S' DISPLAY LIKE 'E' .
ENDIF .
CHECK gt_exp IS NOT INITIAL .
"排序,删除重复维护的字段,活动取值不能有相同的字段
SORT gt_exp BY ref_field ref_table as_table as_field xh .
DELETE ADJACENT DUPLICATES FROM gt_exp COMPARING ref_field as_field.
SORT gt_exp BY xh ref_table ref_field . "删除后按照顺序排好
ENDFORM .
FORM bulid_select .
CLEAR : gv_selea,gv_where,gv_from,gt_field.
LOOP AT gt_exp INTO DATA(ls_exp).
"构造导出至服务器的动态内表的表字段
CLEAR :gs_field .
IF ls_exp-as_field IS NOT INITIAL.
gs_field-fieldname = ls_exp-as_field .
ELSE .
gs_field-fieldname = ls_exp-ref_field .
ENDIF.
gs_field-ref_table = ls_exp-ref_table .
gs_field-ref_field = ls_exp-ref_field .
APPEND gs_field TO gt_field .
"构造动态取值的select字段
IF ls_exp-as_table IS NOT INITIAL.
ls_exp-ref_table = ls_exp-as_table .
ENDIF.
IF gv_selea IS INITIAL.
gv_selea = gv_selea && ls_exp-ref_table && '~' && ls_exp-ref_field .
ELSE .
gv_selea = gv_selea && ',' && ls_exp-ref_table && '~' && ls_exp-ref_field .
ENDIF.
IF ls_exp-as_field IS NOT INITIAL.
gv_selea = gv_selea && ` AS ` && ls_exp-as_field .
ENDIF.
ENDLOOP .
"构造限制条件1代表 限制单值等于某个数据,2代表限制范围
SELECT * FROM ztexport INTO TABLE @DATA(gt_expw) WHERE versi = @p_versi .
LOOP AT gt_expw INTO ls_exp WHERE where_typ IS NOT INITIAL .
IF ls_exp-where_typ = '1'.
IF gv_where IS INITIAL.
CONCATENATE gv_where ls_exp-ref_table '~' ls_exp-ref_field ` = '` ls_exp-where_low `'` INTO gv_where .
ELSE .
CONCATENATE gv_where ` AND ` ls_exp-ref_table '~' ls_exp-ref_field ` = '` ls_exp-where_low `'` INTO gv_where .
ENDIF.
ELSEIF ls_exp-where_typ = '2'.
IF gv_where IS INITIAL.
CONCATENATE gv_where ls_exp-ref_table '~' ls_exp-ref_field ` BETWEEN '` ls_exp-where_low `' AND '` ls_exp-where_high `'` INTO gv_where .
ELSE .
CONCATENATE gv_where ` AND ` ls_exp-ref_table '~' ls_exp-ref_field ` BETWEEN '` ls_exp-where_low `' AND '` ls_exp-where_high `'` INTO gv_where .
ENDIF.
ENDIF.
ENDLOOP.
"构造连表数据
DATA lv_tabix TYPE sy-index .
SELECT DISTINCT ref_table,iffrom FROM ztexport INTO TABLE @DATA(lt_reftab) WHERE versi = @p_versi.
SORT lt_reftab BY iffrom .
LOOP AT lt_reftab INTO DATA(ls_reftab).
"FROM 哪个表
IF ls_reftab-iffrom = 0.
gv_from = ls_reftab-ref_table .
IF ls_exp-as_table IS NOT INITIAL.
gv_selea = gv_selea && ` AS ` && ls_exp-as_table .
ENDIF.
CONTINUE .
ENDIF.
"连接什么表
LOOP AT gt_expw INTO ls_exp WHERE ref_table = ls_reftab-ref_table.
IF ls_exp-join_table IS INITIAL .
CONTINUE .
ENDIF.
lv_tabix = lv_tabix + 1 .
IF lv_tabix = 1.
gv_from = gv_from && ` ` && ls_exp-connet && ` ` && ls_exp-ref_table && ` ON ` .
ENDIF.
IF lv_tabix >= 2 .
gv_from = gv_from && ` AND ` .
ENDIF.
gv_from = gv_from && ` ` && ls_exp-ref_table && '~' && ls_exp-ref_field && ` = ` && ls_exp-join_table && '~' && ls_exp-join_field .
ENDLOOP.
CLEAR : lv_tabix .
ENDLOOP.
"调用方法生成动态内表存储取出的数据
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = gt_field
IMPORTING
ep_table = dy_table.
ASSIGN dy_table->* TO <itab>. "将指针分配给动态内表
CREATE DATA dy_line LIKE LINE OF <itab>.
ASSIGN dy_line->* TO <wa>. "将指针分配给动态内表行
"动态取出数据
IF gv_selea IS NOT INITIAL.
SELECT (gv_selea)
FROM (gv_from)
WHERE (gv_where)
INTO TABLE @<itab> .
ENDIF.
IF <itab> IS INITIAL.
MESSAGE '未找到数据' TYPE 'S' DISPLAY LIKE 'E' .
ENDIF.
ENDFORM .
FORM export_data_to_ser .
CHECK p_serv = 'X' .
DATA lv_lenge TYPE i .
DATA lv_str TYPE string . "用于字段转换位string类型
DATA line TYPE string.""行数据
DATA line1 TYPE string.""第一行表头
DATA lines TYPE string.""表数据
DATA ld_xstring TYPE xstring.
DATA ld_string TYPE string.
DATA wf_msg TYPE string.
TYPES: BEGIN OF ty_fieldname,
name TYPE char20,
END OF ty_fieldname.
DATA: lt_fieldname TYPE TABLE OF ty_fieldname WITH HEADER LINE.
FIELD-SYMBOLS: <lt_table> TYPE table.
CHECK <itab> IS NOT INITIAL .
DATA: lv_file TYPE rlgrap-filename.
DATA: lv_time TYPE n LENGTH 4 .
DATA: p_filename TYPE string .
DATA: lv_assgin TYPE c LENGTH 30 .
DATA: lv_index TYPE sy-index .
SELECT * FROM ztexport INTO TABLE @DATA(lt_expb) .
SORT lt_expb BY xh .
DELETE ADJACENT DUPLICATES FROM lt_expb COMPARING xh .
""取表头描述
SELECT tabname, fieldname, ddtext ,xh FROM dd03m AS a
INNER JOIN @lt_expb AS b ON tabname = b~ref_table AND fieldname = b~ref_field AND ddlanguage = '1'
INTO TABLE @DATA(lt_03m) .
SORT lt_03m BY xh .
DELETE ADJACENT DUPLICATES FROM lt_03m COMPARING xh .
LOOP AT lt_03m INTO DATA(ls_03m).
CONCATENATE line1 ls_03m-ddtext ',' INTO line1 . "每个数据后面加个逗号,excel就会换单元格
ENDLOOP.
" APPEND <WA2> TO <ITAB2> .""函数自带表头传入参数lt_fieldname就会有表头
DATA lv_spaece TYPE string .
lv_spaece = cl_abap_char_utilities=>get_simple_spaces_for_cur_cp( ) . "返回一个带有空白字符的字符串
DO . ""
lv_time = sy-index .
CONCATENATE p_file sy-datum '-' sy-uzeit lv_time '.CSV' INTO lv_file. "服务器保存的目录和文件名
CONCATENATE lines line1 INTO lines . "将表头添加进表
DO p_numb TIMES. "按照凭证上的次数生成文件
UNASSIGN <wa> .
lv_index = lv_index + 1 .
READ TABLE <itab> ASSIGNING <wa> INDEX lv_index .
IF <wa> IS ASSIGNED .
IF p_serv = 'X'. "构造导出到服务器的数据
LOOP AT lt_expb INTO DATA(ls_exp).
CONCATENATE '<WA>-' ls_exp-ref_field INTO lv_assgin .
ASSIGN (lv_assgin) TO FIELD-SYMBOL(<fs_value>) .
IF <fs_value> IS ASSIGNED.
lv_str = <fs_value> . "可能有金额字段,需要转化位字符串
IF ls_exp-del_special = 'X'. "
PERFORM frm_del_str CHANGING lv_str. "" 去掉特殊字符
CONCATENATE line lv_str ',' INTO line . "数字加个单分号会当作文本展示每个数据后面加个逗号,excel就会换单元格
ELSE .
CONCATENATE line lv_str ',' INTO line . "每个数据后面加个逗号,excel就会换单元格
ENDIF.
ENDIF.
ENDLOOP.
" UNASSIGN <WA> .
CONCATENATE lines cl_abap_char_utilities=>cr_lf(1) line INTO lines. "将换行符和这行数据加入表数据中
CLEAR line .
ELSEIF p_loca = 'X'.
MOVE-CORRESPONDING <wa> TO <wa2> .
APPEND <wa2> TO <itab2> .
UNASSIGN: <wa> .
CLEAR :<wa2> .
ENDIF.
ELSE .
EXIT .
ENDIF.
ENDDO.
"每循环一次导出一次数据
IF p_serv = 'X'.
CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
EXPORTING
text = lines
encoding = '8404'
IMPORTING
buffer = ld_xstring
EXCEPTIONS
failed = 1
OTHERS = 2.
" DATA(utf8) = cl_abap_codepage=>convert_to( LINES ). "如果要使用AL11直接下载后台跑出的文件到本地用这个方法转码,而不是上面那个函数
OPEN DATASET lv_file FOR OUTPUT IN BINARY MODE ."TEXT MODE encoding UTF-8
" OPEN DATASET LV_FILE FOR OUTPUT IN TEXT MODE ENCODING UTF-8 WITH BYTE-ORDER MARK."TEXT MODE encoding UTF-8
IF sy-subrc = 0.
TRANSFER ld_xstring TO lv_file.
" TRANSFER LD_XSTRING TO LV_FILE.
CLOSE DATASET lv_file.
MESSAGE '已成功导出至服务器' TYPE 'S' .
ENDIF .
CLEAR : line,lines .
ENDIF.
IF <wa> IS NOT ASSIGNED .
EXIT .
ENDIF.
ENDDO.
CLEAR : lv_index .
ENDFORM .
FORM export_data_to_loc.
CHECK p_loca = 'X' .
DATA lv_lenge TYPE i .
DATA lv_str TYPE string . "用于字段转换位string类型
DATA line TYPE string.""行数据
DATA line1 TYPE string.""第一行表头
DATA lines TYPE string.""表数据
DATA ld_xstring TYPE xstring.
DATA ld_string TYPE string.
DATA wf_msg TYPE string.
CHECK <itab> IS NOT INITIAL .
DATA: lv_file TYPE rlgrap-filename.
DATA: lv_time TYPE n LENGTH 4 .
DATA: p_filename TYPE string .
DATA: lv_assgin TYPE c LENGTH 30 .
DATA: lv_index TYPE sy-index .
TYPES: BEGIN OF ty_fieldname,
name TYPE char20,
END OF ty_fieldname.
DATA: lt_fieldname TYPE TABLE OF ty_fieldname WITH HEADER LINE.
FIELD-SYMBOLS: <lt_table> TYPE table.
LOOP AT gt_exp INTO DATA(ls_exp).
"构造导出至本地的动态内表的表字段 暂时用长度128
CLEAR :gs_field .
IF ls_exp-as_field IS NOT INITIAL.
gs_field-fieldname = ls_exp-as_field .
ELSE .
gs_field-fieldname = ls_exp-ref_field .
ENDIF.
gs_field-inttype = 'C' .
gs_field-intlen = '128' .
APPEND gs_field TO gt_field2 .
ENDLOOP.
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = gt_field2
IMPORTING
ep_table = dy_table2.
ASSIGN dy_table2->* TO <itab2>. "将指针分配给动态内表
CREATE DATA dy_line LIKE LINE OF <itab2>.
ASSIGN dy_line->* TO <wa2>. "将指针分配给动态内表行
""取表头描述
SELECT * FROM ztexport INTO TABLE @DATA(lt_expb) .
SORT lt_expb BY xh .
DELETE ADJACENT DUPLICATES FROM lt_expb COMPARING xh .
SELECT tabname, fieldname, ddtext ,xh FROM dd03m AS a
INNER JOIN @lt_expb AS b ON tabname = b~ref_table AND fieldname = b~ref_field AND ddlanguage = '1'
INTO TABLE @DATA(lt_03m) .
SORT lt_03m BY xh .
DELETE ADJACENT DUPLICATES FROM lt_03m COMPARING xh .
LOOP AT lt_03m INTO DATA(ls_03m).
CONCATENATE '<WA2>-' ls_03m-fieldname INTO lv_assgin .
ASSIGN (lv_assgin) TO FIELD-SYMBOL(<fs_value>) .
IF <fs_value> IS ASSIGNED .
<fs_value> = ls_03m-ddtext .
ENDIF.
UNASSIGN <fs_value> .
lt_fieldname-name = ls_03m-ddtext. "EXCEL表头 LOOP p_table的组件,并依次将字段中文描述赋值给lt_fieldname
APPEND lt_fieldname.
ENDLOOP.
DO . ""
lv_time = sy-index .
DO p_numb TIMES. "按照凭证上的次数生成文件
UNASSIGN <wa> .
lv_index = lv_index + 1 .
READ TABLE <itab> ASSIGNING <wa> INDEX lv_index .
IF <wa> IS ASSIGNED .
MOVE-CORRESPONDING <wa> TO <wa2> .
APPEND <wa2> TO <itab2> .
UNASSIGN: <wa> .
CLEAR :<wa2> .
ELSE .
EXIT .
ENDIF.
ENDDO.
CONCATENATE p_file sy-datum '-' sy-uzeit lv_time '.XLS' INTO lv_file. "服务器保存的目录和文件名
p_filename = lv_file .
CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
filename = p_filename
filetype = 'DAT' "ASC格式 1000- 不会显示为 -1000 DBF格式 字符前空格 前导0不会显示
codepage = '8404' "四位字符集代码 可通过表TCP00A,查询对应字符集代码
TABLES
data_tab = <itab2>
fieldnames = lt_fieldname.
.
MESSAGE '导出成功' TYPE 'S' .
CLEAR: <itab2>.
IF <wa> IS NOT ASSIGNED .
EXIT .
ENDIF.
ENDDO.
CLEAR : lv_index .
ENDFORM .
FORM frm_f4_p_file .
DATA lv_name TYPE c LENGTH 30 .
lv_name = sy-datum && sy-uzeit .
CALL FUNCTION 'WS_FILENAME_GET' "用于选择本地文件,获取本地文件的路径
EXPORTING
def_filename = lv_name "默认的文件名称
* DEF_PATH = ' ' "默认的文件地址
* MASK = ',EXCEL.XLS,*.XLSX,*.XLS,TEXT.TXT,*.TXT.'
mode = 'O' "S 保存 O 打开
title = '选择文件' "窗口的显示名称
IMPORTING "传出给选择屏幕上的文本框
filename = p_file
* RC =
EXCEPTIONS
inv_winsys = 1
no_batch = 2
selection_cancel = 3
selection_error = 4
OTHERS = 5.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ENDFORM .
FORM frm_f4_p_versi .
DATA: gt_return TYPE TABLE OF ddshretval,
gs_return TYPE ddshretval.
DATA: gt_f4 TYPE TABLE OF ztexport,
gs_f4 TYPE ztexport,
gt_f41 TYPE TABLE OF ztexport.
SELECT *
FROM ztexport
INTO TABLE @gt_f4.
DELETE ADJACENT DUPLICATES FROM gt_f4 COMPARING VERSI .
CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
EXPORTING
retfield = 'VERSI'
value_org = 'S'
TABLES
value_tab = gt_f4
return_tab = gt_return
EXCEPTIONS
parameter_error = 1
no_values_found = 2
OTHERS = 3.
IF sy-subrc = 0.
READ TABLE gt_return INTO gs_return INDEX 1.
p_versi = gs_return-fieldval.
ELSE.
ENDIF.
ENDFORM .
FORM frm_del_str CHANGING p_str TYPE string.
REPLACE ALL OCCURRENCES OF ',' IN p_str WITH ` ` .
REPLACE ALL OCCURRENCES OF '#' IN p_str WITH ` ` .
REPLACE ALL OCCURRENCES OF '#' IN p_str WITH ` ` .
REPLACE ALL OCCURRENCES OF ',' IN p_str WITH ` ` .
REPLACE ALL OCCURRENCES OF ',' IN p_str WITH ` ` .
REPLACE ALL OCCURRENCES OF ',' IN p_str WITH ` ` .
DATA(lv_char) = cl_abap_char_utilities=>cr_lf+1(1).
REPLACE ALL OCCURRENCES OF lv_char IN p_str WITH ` ` .
ENDFORM .
FORM FRM_DISPLAY_ALV .
GS_LAYOUT-ZEBRA = 'X'.
" GS_LAYOUT-BOX_FNAME = 'SET'.
* GS_LAYOUT-STYLEFNAME = 'STYLE'.
GS_LAYOUT-CWIDTH_OPT = 'X'.
GS_VARIANT-REPORT = SY-REPID.
GS_VARIANT-HANDLE = '0001'.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
I_CALLBACK_PROGRAM = SY-REPID
IT_FIELDCAT_LVC = GT_FIELD
IS_LAYOUT_LVC = GS_LAYOUT
" IT_EVENTS = GT_EVENTS
IS_VARIANT = GS_VARIANT
* I_CALLBACK_TOP_OF_PAGE = 'FRM_TOP_OF_PAGE'
* I_CALLBACK_USER_COMMAND = 'FRM_USER_COMMAND'
I_CALLBACK_PF_STATUS_SET = 'FRM_SET_STATUS'
" I_SAVE = 'A'
I_DEFAULT = 'X'
TABLES
T_OUTTAB = <ITAB>.
ENDFORM .
FORM FRM_SET_STATUS USING P_EXTAB TYPE SLIS_T_EXTAB .
SET PF-STATUS 'STATU'.
SET TITLEBAR 'STATU'.
ENDFORM.
配置表如下
参考配置表数据如下
选择屏幕文本
配置表各个字段的作用
版本VERSI及版本行项目:
用来区别本次导出是导出什么表
版本描述:
描述该版本是导出哪个表的数据
导出展示位置XH:
导出的文件中表头顺序按照该数字排序
导出表格REF_TABLE及导出字段REF_FIELD:
导出的数据从哪个表格字段取数
表别名AS_TABLE,字段别名AS_FIELD:
动态sql不能有完全一样的字段,当字段一样时要是要别名
连表顺序(FROM为0,依次往后加)IFFROM:
sql中连表的顺序
连表方式CONNET:
LEFT JOIN ,INNER JOIN 等
连接的表名JOIN_TABLE,连接的字段名JOIN_FIELD:
与连表方式共同组成连表
限制类型WHERE_TYP,限制条件LOW( WHERE_LOW),限制条件HIGH( WHERE_HIGH):
当限制类型等于1时代表限制该字段等于限制条件low值,当限制类型等于2时,代表限制该字段为范围low至high中的数据。
X代表用空格代替特殊字符后导出DEL_SPECIAL:
有的数据再导出是如果存在特殊字符则无法导出到excel或者格式出错,若维护了该字段等于X则代码帮助去除特殊字符,可在form中新增特殊字符。
主要代码讲解
程序总体逻辑:根据配置表构造活动sql的select语句,讲取到的数据存储到活动内表,然后对活动内表进行处理,导出数据到本地,或者sap服务器。
活动sql
sql语句由四部分组成 select ... from ... where... into ... ,sap可以使用字符串代替这四部分,本程序运用此特性将维护表数据构造成活动sql取值
活动内表
类方法cl_alv_table_create=>create_dynamic_table 传入参考的字段清单即可构造成动态内表,将结果构造成与上文的sql结构一致,即可不浪费内存,不浪费算力存储数据
二进制数据流数据导出
将数据按照格式构造成二进制数据流的方式,然后导出到sap服务器能访问的地址
CALL FUNCTION 'SCMS_STRING_TO_XSTRING 为数据转码,
OPEN DATASET lv_file FOR OUTPUT IN BINARY MODE . 打开文件位置路径为 lv_file
TRANSFER ld_xstring TO lv_file. 将文件ld_xstring 写入刚刚打开的位置 lv_file
CLOSE DATASET lv_file. 写入完成后关闭连接
本文构造的是csv格式的excel文件,该格式由一个字符串组成,空格代表下一个单元格 ,调用方法 cl_abap_char_utilities=>cr_lf(1) 代表换行,数据构造速度快,但是缺点是其他的格式都是默认的无法修改。
导出至本地调用的是函数 GUI_DOWNLOAD ,比较简单在此不在赘述
常驻sap欢迎留言