声明:本文仅代表原作者观点,仅用于SAP应用和交流,不代表任何公司。
小甲:老师,我最近很郁闷,你作为国内的ABAP一哥,给我指条路吧。小甲:我不是在做ABAP报表优化嘛,本来一切都很顺利,直到有一个大量使用了长文本的报表,卡壳了。这个报表不仅要取很多长文本数据,而且还要根据里面的值做筛选,我想不到有什么好办法优化了。
小甲:就是使用READ_TEXT挨个订单号取啊,难道还有其他的办法吗?老白:READ_TEXT是取少量长文本使用的,你要是有大量长文本需要取数就不能使用这个函数了,你还记得我给你说过数据库取数相关的优化有个原则是啥不?
小甲:老师我知道你要说啥,不就是减少IO嘛?可是长文本使用了数据簇的方式存储,没有办法批量直接在DB取出来,只能一个一个取数呀。老白:是的,你说的方向的对的,只是不知道如何批量取数而已。(转头面对观众)实际上呢,READ_TEXT把数据抬头存到表STXH,使用的是正常的存储方式,而真正的长文本内容在表STXL,这个就是数据簇的方式了,也就是读写都比较特殊,需要用EXPORT xxxx TO DATABASE xxx(xx) ID....,IMPORT xxxx FROM DATABASE xxx(xx) ID....这种方式去写入或者读取,而且这个不支持批量读取,(转回头)也就是你说的只能一个一个取数了。小甲:是的呀老师,这不就废了嘛,一条无法逾越的鸿沟挡住了优化的道路,我可咋办啊,嘤嘤嘤。。。老白:你看你怎么还哭上了,我给你说过的ABAP优化第一原则是啥你还记得不?小甲:记得,第一原则就是ABAP优化没有尽头,只要你想,总归有方法的。不过我感觉这次是到了尽头了,没得吹了,标准的不支持咋办呢?老白:数据簇的DB格式不是不支持批量读取,只是没有直接的语法支持而已,我们可以通过变通的方法达到我们的目的,你还记得有个IMPORT xxxx FROM INTERNAL TABLE... 的语法不?小甲:没有用过哎,不过看上去这个是在内表取数的,跟DB不是一回事啊,不过既然你都问我这个了,那肯定就是用它变通了呗。
老白:对头,孺子可教!你可以先把数据批量在STXL取到内表,然后使用IMPORT xxxx FROM INTERNAL TABLE如此这般这般一通操作,就行了。
小甲:?什么这般那般的?怎么就行了?老师你不要给我打哑谜啊,用一两句话给我简简单单讲明白讲透彻就行了。
老白:一两句话要是能讲明白讲透彻我还逼逼这么多干嘛,还是看代码吧。(面对观众)下面代码是利用销售订单的长文本来做一个优化方案和标准取数的对比,直接复制到色38就可以执行看看效果了,有一点要注意哈,其他老师也有讲这个办法的,但是大多都忽略了两个重点,一个是STXL的数据可能有多行,也就是STXL-SRTF2大于0的情况,另一个是如果是复制的长文本,也就是STXH-TDREF = 'X'的时候,需要使用TDREFOBJ、TDREFNAME、TDREFID去STXL取数,另外如果你的系统比较新,可以看看有没有函数READ_TEXT_TABLE,这个函数也可以批量读取,原理是一样的。*&---------------------------------------------------------------------*
*& 对比两种方式读取长文本的性能
*& Baitianzhen *
*&---------------------------------------------------------------------*
REPORT zlong_text NO STANDARD PAGE HEADING.
TABLES:vbak.
DATA: BEGIN OF gt_ltext OCCURS 0,
tdobject TYPE stxh-tdobject,
tdname TYPE stxh-tdname,
tdid TYPE stxh-tdid,
tdspras TYPE stxh-tdspras,
tlines TYPE string,
END OF gt_ltext.
DATA: gt_ltext2 LIKE gt_ltext[] WITH HEADER LINE.
DATA: t1 TYPE i,
t2 TYPE i.
DATA: gt_vbeln TYPE TABLE OF vbeln WITH HEADER LINE.
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln,
s_erdat FOR vbak-erdat DEFAULT sy-datum.
START-OF-SELECTION.
SELECT vbeln INTO TABLE gt_vbeln
FROM vbak
WHERE vbeln IN s_vbeln AND
erdat IN s_erdat.
WRITE: '订单条数:',sy-dbcnt.
LOOP AT gt_vbeln.
gt_ltext-tdobject = 'VBBK'.
gt_ltext-tdname = gt_vbeln.
gt_ltext-tdid = '0001'.
gt_ltext-tdspras = '1'.
APPEND gt_ltext.
gt_ltext-tdobject = 'VBBK'.
gt_ltext-tdname = gt_vbeln.
gt_ltext-tdid = '0002'.
gt_ltext-tdspras = '1'.
APPEND gt_ltext.
ENDLOOP.
gt_ltext2[] = gt_ltext[].
GET RUN TIME FIELD t1.
PERFORM get_long_text_fm TABLES gt_ltext.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: / '使用标准函数所用时间:', t1.
GET RUN TIME FIELD t1.
PERFORM get_long_text_im TABLES gt_ltext2.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: / '使用优化方案所用时间:', t1.
*&---------------------------------------------------------------------*
*& 使用标准函数的方式读取
*&---------------------------------------------------------------------*
FORM get_long_text_fm TABLES t_ltext STRUCTURE gt_ltext.
DATA lt_tline TYPE TABLE OF tline WITH HEADER LINE.
CHECK t_ltext[] IS NOT INITIAL.
SELECT tdobject tdname tdid tdspras
INTO TABLE t_ltext
FROM stxh
FOR ALL ENTRIES IN t_ltext
WHERE tdobject = t_ltext-tdobject AND
tdid = t_ltext-tdid AND
tdspras = t_ltext-tdspras AND
tdname = t_ltext-tdname.
IF sy-subrc = 0.
LOOP AT t_ltext.
CLEAR lt_tline[].
CALL FUNCTION 'READ_TEXT'
EXPORTING
id = t_ltext-tdid
language = t_ltext-tdspras
name = t_ltext-tdname
object = t_ltext-tdobject
TABLES
lines = lt_tline
EXCEPTIONS
OTHERS = 8.
LOOP AT lt_tline.
CONCATENATE t_ltext-tlines lt_tline-tdline INTO t_ltext-tlines.
ENDLOOP.
IF t_ltext-tlines IS INITIAL.
DELETE t_ltext.
CONTINUE.
ELSE.
MODIFY t_ltext.
ENDIF.
ENDLOOP.
ELSE.
CLEAR t_ltext[].
ENDIF.
ENDFORM. "get_long_text_fm
*&---------------------------------------------------------------------*
*& 优化方案
*&---------------------------------------------------------------------*
FORM get_long_text_im TABLES t_ltext STRUCTURE gt_ltext.
DATA: BEGIN OF lt_stxh OCCURS 0,
tdobject TYPE stxh-tdobject ,
tdname TYPE stxh-tdname ,
tdid TYPE stxh-tdid ,
tdspras TYPE stxh-tdspras ,
tdrefobj TYPE stxh-tdrefobj ,
tdrefname TYPE stxh-tdrefname,
tdrefid TYPE stxh-tdrefid ,
END OF lt_stxh.
DATA: BEGIN OF lt_key OCCURS 0,
tdobject TYPE stxl-tdobject,
tdname TYPE stxl-tdname,
tdid TYPE stxl-tdid,
tdspras TYPE stxl-tdspras,
END OF lt_key.
DATA: BEGIN OF lt_stxl OCCURS 0,
tdobject TYPE stxl-tdobject,
tdid TYPE stxl-tdid,
tdname TYPE stxl-tdname,
tdspras TYPE stxl-tdspras,
srtf2 TYPE stxl-srtf2 ,
clustr TYPE stxl-clustr,
clustd TYPE stxl-clustd,
END OF lt_stxl.
DATA: BEGIN OF lt_clust OCCURS 0,
clustr TYPE stxl-clustr,
clustd TYPE stxl-clustd,
END OF lt_clust.
DATA lt_tline TYPE TABLE OF tline WITH HEADER LINE.
CHECK t_ltext[] IS NOT INITIAL.
SELECT tdobject tdname tdid tdspras
tdrefobj tdrefname tdrefid
INTO TABLE lt_stxh
FROM stxh
FOR ALL ENTRIES IN t_ltext
WHERE tdobject = t_ltext-tdobject AND
tdid = t_ltext-tdid AND
tdspras = t_ltext-tdspras AND
tdname = t_ltext-tdname.
IF sy-subrc = 0.
LOOP AT lt_stxh.
IF lt_stxh-tdrefname = ''.
lt_key-tdobject = lt_stxh-tdobject.
lt_key-tdname = lt_stxh-tdname.
lt_key-tdid = lt_stxh-tdid.
ELSE.
lt_key-tdobject = lt_stxh-tdrefobj .
lt_key-tdname = lt_stxh-tdrefname.
lt_key-tdid = lt_stxh-tdrefid .
ENDIF.
lt_key-tdspras = lt_stxh-tdspras.
COLLECT lt_key.
ENDLOOP.
CHECK lt_key[] IS NOT INITIAL.
SELECT tdobject tdid tdname tdspras srtf2 clustr clustd
INTO TABLE lt_stxl
FROM stxl
FOR ALL ENTRIES IN lt_key
WHERE relid = 'TX' AND
tdobject = lt_key-tdobject AND
tdid = lt_key-tdid AND
tdname = lt_key-tdname AND
tdspras = lt_key-tdspras.
SORT lt_stxl BY tdobject tdid tdname srtf2.
CLEAR t_ltext[].
LOOP AT lt_stxh.
CLEAR: lt_clust[],lt_tline[].
IF lt_stxh-tdrefname = ''.
READ TABLE lt_stxl WITH KEY tdobject = lt_stxh-tdobject
tdid = lt_stxh-tdid
tdname = lt_stxh-tdname
tdspras = lt_stxh-tdspras
BINARY SEARCH.
IF sy-subrc = 0.
LOOP AT lt_stxl FROM sy-tabix.
IF lt_stxl-tdobject NE lt_stxh-tdobject OR
lt_stxl-tdid NE lt_stxh-tdid OR
lt_stxl-tdname NE lt_stxh-tdname OR
lt_stxl-tdspras NE lt_stxh-tdspras.
EXIT.
ENDIF.
lt_clust-clustr = lt_stxl-clustr.
lt_clust-clustd = lt_stxl-clustd.
APPEND lt_clust.
ENDLOOP.
IMPORT tline = lt_tline FROM INTERNAL TABLE lt_clust.
ENDIF.
ELSE.
READ TABLE lt_stxl WITH KEY tdobject = lt_stxh-tdrefobj
tdid = lt_stxh-tdrefid
tdname = lt_stxh-tdrefname
tdspras = lt_stxh-tdspras
BINARY SEARCH.
IF sy-subrc = 0.
LOOP AT lt_stxl FROM sy-tabix.
IF lt_stxl-tdname NE lt_stxh-tdrefname OR
lt_stxl-tdobject NE lt_stxh-tdrefobj OR
lt_stxl-tdid NE lt_stxh-tdrefid OR
lt_stxl-tdspras NE lt_stxh-tdspras.
EXIT.
ENDIF.
lt_clust-clustr = lt_stxl-clustr.
lt_clust-clustd = lt_stxl-clustd.
APPEND lt_clust.
ENDLOOP.
IMPORT tline = lt_tline FROM INTERNAL TABLE lt_clust.
ELSE.
CALL FUNCTION 'READ_TEXT'
EXPORTING
id = lt_stxh-tdrefid
language = lt_stxh-tdspras
name = lt_stxh-tdrefname
object = lt_stxh-tdrefobj
TABLES
lines = lt_tline
EXCEPTIONS
OTHERS = 8.
ENDIF.
ENDIF.
t_ltext-tdobject = lt_stxh-tdobject.
t_ltext-tdname = lt_stxh-tdname .
t_ltext-tdid = lt_stxh-tdid .
t_ltext-tdspras = lt_stxh-tdspras .
LOOP AT lt_tline.
CONCATENATE t_ltext-tlines lt_tline-tdline INTO t_ltext-tlines.
ENDLOOP.
CHECK t_ltext-tlines IS NOT INITIAL.
APPEND t_ltext. CLEAR t_ltext.
ENDLOOP.
ELSE.
CLEAR t_ltext[].
ENDIF.
ENDFORM. "get_long_text_im
小甲:老师,结果出来了!提升了大概3到4倍的效率,感觉虽然还行,但不是特别的惊艳啊,没有达到那种让人情不自禁“哇塞”一声是效果哈,这种提升效果不符合你的身份哦!
老白:你小子还学会激将法了?看来不给你来点狠活是不行了,你知道江湖上的一句传言不?老白:那就是著名的一类优化方法:用空间换时间!具体来说呢,就是把需要的数据按照需要的格式整理好放到表里面,等需要的时候直接根据主键来拿就行了,速度那是非常的快啊。小甲:老师你这么一说我茅厕顿开了!SAP的信息结构(Information structures),就像S022,S039这种表,也是这个思路,我当初还做过好多个呢!那玩意确实好用,牺牲有点磁盘空间就能获取取数的极大快感,值!不过长文本似乎没法做信息结构啊老白:还茅厕顿开,你还是赶紧把茅厕关上吧,味儿都传出来了啊喂!那是茅塞顿开!老白:当然是用增强咯,当然你要是觉着无所谓直接改源码也行。首先创建一个表来存放长文本数据,这个表的关键是存放长文本的字段,这个字段的定义非常有讲究,如果是定义短了呢,稍微长点的文本内容就放不下,要是太长呢,S4支持最大30000,一篇论文都能放得下了,但是如果你的系统是ECC,仅仅能支持到1333长度,那肯定不大够。如果是定义成STRING呢,倒是不用担心长度问题了,但是在SQL的SELECT中又不能用来限制数据的读取了,所以,如果是S4,直接定义一个长的字段就妥了,如果是ECC就麻烦很多,建议可以像下面这样定义:
小甲:这样挺好老师,兼顾了所有长度文本的存储和大多数长文本的SQL取数限制需求,而且还有长度字段,可以知道这个TLINE是不是只存了一部分内容。要是S4,把TLINE定义好长好长,TLSTR就不需要了。
老白:是的,下面是增强程序的修改,需要修改函数COMMIT_TEXT
DATA: ls_zltxt TYPE zltxt.
LOOP AT catalog WHERE tdobject IN r_object
AND tdname IN r_name
AND tdid IN r_id
AND tdspras IN r_language.
DELETE FROM zltxt
WHERE tdobject = catalog-tdobject AND
tdname = catalog-tdname AND
tdid = catalog-tdid AND
tdspras = catalog-tdspras.
CHECK catalog-function NE function_delete.
memory_id+8(6) = catalog-id.
CLEAR clines[].
IMPORT tline TO clines FROM MEMORY ID memory_id.
CHECK sy-subrc = 0.
CLEAR ls_zltxt.
ls_zltxt-tdobject = catalog-tdobject.
ls_zltxt-tdname = catalog-tdname.
ls_zltxt-tdid = catalog-tdid.
ls_zltxt-tdspras = catalog-tdspras.
LOOP AT clines.
CONCATENATE ls_zltxt-tlstr clines-tdline INTO ls_zltxt-tlstr.
ENDLOOP.
ls_zltxt-tsize = strlen( ls_zltxt-tlstr ).
ls_zltxt-tline = ls_zltxt-tlstr.
INSERT zltxt FROM ls_zltxt.
ENDLOOP.
小甲:老师你好大的胆子呀,不是说不让直接修改源码吗?说修改了源码系统升级的时候容易给覆盖掉,还得做SPAU。老白:年轻人,胆子可以大一点嘛,只要你完全知道你做的事儿对系统有啥影响,也可以适当改改源码,不过最推荐的办法还是增强哈,或者隐式增强。小甲:Get!我弄点测试数据看看是不是已经存到表里了哈。哦也,果然可以了!老白:是的,这下你就可以直接JOIN这个表来取数了,是不是特别爽?小甲:那是相当的爽啊,速度要提升几百倍啦!这点磁盘空间用的值!不过老师,似乎还有点问题呢,,,
小甲:第一、我不想每个类型的长文本都存储,因为我用不到,白白占用磁盘空间,还拖慢了存取数的速度。第二、TDNAME这个字段是KEY字段的组合,在S4可以用concat关键字查询,ECC不行啊。第三、历史数据咋办呢?增强又不会把历史数据弄进去?老白:第一个问题好办,弄一个配置表就行了,需要保存的OBJECT维护到表里面,在增强里面判断一下再保存。第二个问题有点棘手,如果你对性能极度渴望呢,就再新建你需要主键的表,增强保存的拆分KEY数据放到这个新表,如果性能要求不是那么极端呢,用FOR ALL ENTRIES也是可以的。至于第三个,肯定得有一个配套的初始化/检查程序嘛。小甲:老师牛逼!这下又可以愉快的写着代码唱着歌,哈哈哈。另外,我发现还有两个微信群可以扫码加入,想讨论的小伙伴可以加入哈。*&---------------------------------------------------------------------*
*& Report ZLTXT_INIT
*&
*&---------------------------------------------------------------------*
*& 长文本增强工具程序
*& Baitianzhen
*&---------------------------------------------------------------------*
REPORT zltxt_init NO STANDARD PAGE HEADING LINE-SIZE 1023.
TABLES stxh.
DATA: gt_fldct TYPE lvc_t_fcat,
gs_slayt TYPE lvc_s_layo,
gs_varnt TYPE disvariant,
gv_repid TYPE sy-repid.
DATA: gt_stxh TYPE TABLE OF zltxt WITH HEADER LINE.
DATA: gt_ltxt TYPE TABLE OF zltxt WITH HEADER LINE.
DATA: gt_line TYPE TABLE OF tline WITH HEADER LINE.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE btxt2.
PARAMETERS: pr_init RADIOBUTTON GROUP g1 USER-COMMAND r1.
PARAMETERS: pr_chck RADIOBUTTON GROUP g1 DEFAULT 'X'.
PARAMETERS: pr_disp RADIOBUTTON GROUP g1.
SELECTION-SCREEN END OF BLOCK b2.
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE btxt1.
SELECT-OPTIONS: s_obj FOR stxh-tdobject DEFAULT 'VBBK',
s_id FOR stxh-tdid ,
s_spras FOR stxh-tdspras ,
s_name FOR stxh-tdname ,
s_date FOR stxh-tdfdate MODIF ID b,
s_size FOR gt_ltxt-tsize MODIF ID a,
s_line FOR gt_ltxt-tline MODIF ID a.
SELECTION-SCREEN END OF BLOCK b1.
AT SELECTION-SCREEN OUTPUT.
btxt1 = '数据筛选'.
btxt2 = '功能'.
%_s_obj_%_app_%-text = '应用程序对象'.
%_s_id_%_app_%-text = '文本标识'.
%_s_spras_%_app_%-text = '语言'.
%_s_name_%_app_%-text = '名称'.
%_s_date_%_app_%-text = '创建日期'.
%_s_size_%_app_%-text = '文本长度'.
%_s_line_%_app_%-text = '文本内容(前132字符)'.
%_pr_init_%_app_%-text = '初始化'.
%_pr_chck_%_app_%-text = '检查数据'.
%_pr_disp_%_app_%-text = '显示ZLTXT表内容'.
LOOP AT SCREEN.
CASE 'X'.
WHEN pr_init OR pr_chck.
IF screen-group1 CA 'A'.
screen-active = '0'.
ENDIF.
WHEN OTHERS.
IF screen-group1 CA 'B'.
screen-active = '0'.
ENDIF.
ENDCASE.
MODIFY SCREEN.
ENDLOOP.
START-OF-SELECTION.
CASE 'X'.
WHEN pr_init OR pr_chck.
PERFORM get_stxh_data.
WHEN pr_disp.
PERFORM show_zltxt.
PERFORM outdata.
ENDCASE.
*&---------------------------------------------------------------------*
*& Form get_stxh_data
*&---------------------------------------------------------------------*
FORM get_stxh_data.
DATA: BEGIN OF lt_stxh OCCURS 0,
tdobject TYPE stxh-tdobject ,
tdname TYPE stxh-tdname ,
tdid TYPE stxh-tdid ,
tdspras TYPE stxh-tdspras ,
tdrefobj TYPE stxh-tdrefobj ,
tdrefname TYPE stxh-tdrefname,
tdrefid TYPE stxh-tdrefid ,
tdfdate TYPE stxh-tdfdate ,
END OF lt_stxh.
DATA: BEGIN OF lt_key OCCURS 0,
tdobject TYPE stxl-tdobject,
tdname TYPE stxl-tdname,
tdid TYPE stxl-tdid,
tdspras TYPE stxl-tdspras,
END OF lt_key.
DATA: BEGIN OF lt_stxl OCCURS 0,
tdobject TYPE stxl-tdobject,
tdid TYPE stxl-tdid,
tdname TYPE stxl-tdname,
tdspras TYPE stxl-tdspras,
srtf2 TYPE stxl-srtf2 ,
clustr TYPE stxl-clustr,
clustd TYPE stxl-clustd,
END OF lt_stxl.
DATA: BEGIN OF lt_clust OCCURS 0,
clustr TYPE stxl-clustr,
clustd TYPE stxl-clustd,
END OF lt_clust.
DATA: lv_cursor TYPE cursor,
lv_dbcntr TYPE i.
OPEN CURSOR WITH HOLD lv_cursor FOR
SELECT tdobject tdname tdid tdspras
tdrefobj tdrefname tdrefid tdfdate
FROM stxh
WHERE tdobject IN s_obj AND
tdid IN s_id AND
tdspras IN s_spras AND
tdname IN s_name AND
tdfdate IN s_date.
DO.
FETCH NEXT CURSOR lv_cursor INTO TABLE lt_stxh PACKAGE SIZE 10000.
IF sy-subrc NE 0.
EXIT.
ENDIF.
lv_dbcntr = sy-dbcnt.
CLEAR: lt_key[],lt_stxl[],gt_stxh[],gt_stxh.
LOOP AT lt_stxh.
IF lt_stxh-tdrefname = ''.
lt_key-tdobject = lt_stxh-tdobject.
lt_key-tdname = lt_stxh-tdname.
lt_key-tdid = lt_stxh-tdid.
ELSE.
lt_key-tdobject = lt_stxh-tdrefobj .
lt_key-tdname = lt_stxh-tdrefname.
lt_key-tdid = lt_stxh-tdrefid .
ENDIF.
lt_key-tdspras = lt_stxh-tdspras.
COLLECT lt_key.
ENDLOOP.
CHECK lt_key[] IS NOT INITIAL.
SELECT tdobject tdid tdname tdspras srtf2 clustr clustd
INTO TABLE lt_stxl
FROM stxl
FOR ALL ENTRIES IN lt_key
WHERE relid = 'TX' AND
tdobject = lt_key-tdobject AND
tdid = lt_key-tdid AND
tdname = lt_key-tdname AND
tdspras = lt_key-tdspras.
SORT lt_stxl BY tdobject tdid tdname tdspras srtf2.
LOOP AT lt_stxh.
CLEAR: lt_clust[],gt_line[],gt_line.
IF lt_stxh-tdrefname = ''.
READ TABLE lt_stxl WITH KEY tdobject = lt_stxh-tdobject
tdid = lt_stxh-tdid
tdname = lt_stxh-tdname
tdspras = lt_stxh-tdspras
BINARY SEARCH.
IF sy-subrc = 0.
LOOP AT lt_stxl FROM sy-tabix.
IF lt_stxl-tdobject NE lt_stxh-tdobject OR
lt_stxl-tdid NE lt_stxh-tdid OR
lt_stxl-tdname NE lt_stxh-tdname OR
lt_stxl-tdspras NE lt_stxh-tdspras.
EXIT.
ENDIF.
lt_clust-clustr = lt_stxl-clustr.
lt_clust-clustd = lt_stxl-clustd.
APPEND lt_clust.
ENDLOOP.
IMPORT tline = gt_line FROM INTERNAL TABLE lt_clust.
ENDIF.
ELSE.
READ TABLE lt_stxl WITH KEY tdobject = lt_stxh-tdrefobj
tdid = lt_stxh-tdrefid
tdname = lt_stxh-tdrefname
tdspras = lt_stxh-tdspras
BINARY SEARCH.
IF sy-subrc = 0.
LOOP AT lt_stxl FROM sy-tabix.
IF lt_stxl-tdname NE lt_stxh-tdrefname OR
lt_stxl-tdobject NE lt_stxh-tdrefobj OR
lt_stxl-tdid NE lt_stxh-tdrefid OR
lt_stxl-tdspras NE lt_stxh-tdspras.
EXIT.
ENDIF.
lt_clust-clustr = lt_stxl-clustr.
lt_clust-clustd = lt_stxl-clustd.
APPEND lt_clust.
ENDLOOP.
IMPORT tline = gt_line FROM INTERNAL TABLE lt_clust.
ELSE.
CALL FUNCTION 'READ_TEXT'
EXPORTING
id = lt_stxh-tdrefid
language = lt_stxh-tdspras
name = lt_stxh-tdrefname
object = lt_stxh-tdrefobj
TABLES
lines = gt_line
EXCEPTIONS
OTHERS = 8.
ENDIF.
ENDIF.
gt_stxh-tdobject = lt_stxh-tdobject.
gt_stxh-tdname = lt_stxh-tdname .
gt_stxh-tdid = lt_stxh-tdid .
gt_stxh-tdspras = lt_stxh-tdspras .
LOOP AT gt_line.
CONCATENATE gt_stxh-tlstr gt_line-tdline INTO gt_stxh-tlstr.
ENDLOOP.
gt_stxh-tsize = strlen( gt_stxh-tlstr ).
gt_stxh-tline = gt_stxh-tlstr.
CHECK gt_stxh-tline IS NOT INITIAL.
APPEND gt_stxh. CLEAR gt_stxh.
ENDLOOP.
CHECK gt_stxh[] IS NOT INITIAL.
CASE 'X'.
WHEN pr_init.
MODIFY zltxt FROM TABLE gt_stxh.
WHEN pr_chck.
PERFORM check_data.
ENDCASE.
CALL FUNCTION 'DB_COMMIT'.
MESSAGE s000(oo) WITH '累计处理完条数:' lv_dbcntr.
ENDDO.
CLOSE CURSOR lv_cursor.
ENDFORM. "get_stxh_data
*&---------------------------------------------------------------------*
*& Form CHECK_DATA
*&---------------------------------------------------------------------*
FORM check_data.
CLEAR gt_ltxt[].
SELECT * INTO TABLE gt_ltxt
FROM zltxt
FOR ALL ENTRIES IN gt_stxh
WHERE tdobject = gt_stxh-tdobject AND
tdid = gt_stxh-tdid AND
tdspras = gt_stxh-tdspras AND
tdname = gt_stxh-tdname.
SORT gt_stxh BY tdobject tdname tdid tdspras.
SORT gt_ltxt BY tdobject tdname tdid tdspras.
SKIP.
LOOP AT gt_stxh.
READ TABLE gt_ltxt WITH KEY tdobject = gt_stxh-tdobject
tdname = gt_stxh-tdname
tdid = gt_stxh-tdid
tdspras = gt_stxh-tdspras
BINARY SEARCH.
IF sy-subrc = 0.
IF gt_stxh-tlstr = gt_ltxt-tlstr.
DELETE gt_ltxt INDEX sy-tabix.
DELETE gt_stxh.
CONTINUE.
ELSE.
WRITE: / '应该:',gt_stxh-tdobject,gt_stxh-tdid,
gt_stxh-tdname,gt_stxh-tlstr.
WRITE: / '现值:',gt_ltxt-tdobject,gt_ltxt-tdid,
gt_ltxt-tdname,gt_ltxt-tlstr.
ENDIF.
ENDIF.
ENDLOOP.
SKIP.
LOOP AT gt_stxh FROM 1 TO 10.
WRITE: / '缺少:',gt_stxh-tdobject,gt_stxh-tdid,gt_stxh-tdname,
gt_stxh-tdspras, AT 92 gt_stxh-tlstr.
ENDLOOP.
ENDFORM. " CHECK_DATA
*&---------------------------------------------------------------------*
*& Form show_zltxt
*&---------------------------------------------------------------------*
FORM show_zltxt.
SELECT * INTO TABLE gt_ltxt FROM zltxt
WHERE tdobject IN s_obj AND
tdid IN s_id AND
tdspras IN s_spras AND
tdname IN s_name AND
tsize IN s_size AND
tline IN s_line.
ENDFORM. "show_zltxt
*&---------------------------------------------------------------------*
*& Form outdata
*&---------------------------------------------------------------------*
FORM outdata.
gv_repid = sy-repid.
gs_slayt-zebra = 'X'.
gs_slayt-detailinit = 'X'.
gs_slayt-cwidth_opt = 'X'.
gs_varnt-report = sy-repid.
gs_varnt-handle = 1.
CHECK gt_ltxt[] IS NOT INITIAL.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
i_structure_name = 'ZLTXT'
i_save = 'A'
is_variant = gs_varnt
is_layout_lvc = gs_slayt
i_callback_program = gv_repid
i_callback_user_command = 'USER_COMMAND'
TABLES
t_outtab = gt_ltxt.
ENDFORM. " outdata
*&--------------------------------------------------------------------*
*& Form user_command
*&--------------------------------------------------------------------*
FORM user_command USING pv_ucomm TYPE sy-ucomm
pv_field TYPE slis_selfield.
* DATA lt_text TYPE catsxt_longtext_itab.
DATA lt_text TYPE TABLE OF tdline WITH HEADER LINE.
READ TABLE gt_ltxt INDEX pv_field-tabindex.
CASE pv_ucomm.
WHEN '&IC1'.
CASE pv_field-fieldname.
WHEN 'TLSTR' OR 'TLINE'.
CALL FUNCTION 'READ_TEXT'
EXPORTING
id = gt_ltxt-tdid
language = gt_ltxt-tdspras
name = gt_ltxt-tdname
object = gt_ltxt-tdobject
TABLES
lines = gt_line
EXCEPTIONS
OTHERS = 8.
IF sy-subrc NE 0.
MESSAGE ID sy-msgid TYPE 'E' NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ELSE.
LOOP AT gt_line.
APPEND gt_line-tdline TO lt_text.
ENDLOOP.
CALL FUNCTION 'TERM_CONTROL_EDIT'
TABLES
textlines = lt_text
EXCEPTIONS
user_cancelled = 1.
ENDIF.
ENDCASE.
ENDCASE.
ENDFORM. "user_command
免责声明:本文所用视频、图片、文字如涉及作品版权问题,请第一时间告知,我们将根据您提供的证明材料确认版权并按国家标准支付稿酬或立即删除内容!本文内容为原作者观点,并不代表本公众号赞同其观点和对其真实性负责。