原创 无峰 [ ABAP 技巧与实战 ](javascript:void\(0\);)
一
前言
动态报表D-Query 是一个用于取代标准QUERY的程序.使用动态报表无需写代码,非开发人员也可生成专业的报表程序.
> 详见动态报表简介 无峰,公众号:ABAP 技巧与实战 [ 动态报表D-Query简介
> ](https://mp.weixin.qq.com/s?__biz=Mzg4MjA1MjE4NQ==&mid=2247486429&idx=1&sn=8cbab08040255baa4c7495e6e106230d&chksm=cf5dd6ebf82a5ffdf6cd2cca5ef3b3a298dcb7e3aac2b4cae5073af9c6720bf57b5544c57a49&token=220549748&lang=zh_CN#rd)
**本文主要介绍通过字频应用优化字段的选择**
_这个念头有了很久了. 最近才付诸实施_
二
缘起
动态报表可以很方便的通过勾选的方式产生报表.但某些标准表往往字段很多,在对表字段不熟悉的情况下, 勾选想要的字段存在一定的麻烦.
比如EKKO表有205个字段. EKPO 有421个字段
动态报表中如果使用了EKKO表, 会显示EKKO的所有字段,这给动态报表的设置带来了一定的麻烦. 如果关联了EKPO表.
则需要在更多的字段中选择所需的字段.
通过查看数据发现, 大部分的字段是空值.
三
念起
那怎么能够改进这个字段选择的过程呢? 方法很简单, 隐去无用的字段. 大致两个方式
• 方式一:创建视图,仅包含有用的字段
• 方式二:计算字段的字频,通过字频过滤字段
_**01** _
**方式一**
比如MARA表字段很多. 但是在特定项目中 ,往往只有部分字段使用.
因此可以通过视图(SE11或CDS视图)把所有有用的字段集合起来. 后续通过视图访问物料属性.
这种方式非常有效,在项目初期创建此类视图,可以让后续的开发更简洁. 但是由此也带来了相应的工作量(前期创建视图, 后期调整视图,补充字段).
动态报表中可以直接使用视图参与关联.
_**01** _
**方式二**
引入并调整一个概念: 字频
转义后的字频概念: 字段在表中出现的不同值个数
字频的优化, 如果字频统计为1 且字段类型为字符,值为空. 则调整字频为0
这样,就可以通过字频来识别字段是否有用.
四
念生
把字频概念引入到动态报表中. 允许用户实时统计字频并根据字频过滤字段. 这样动态报表仅呈现有用的字段,可以很大程度上方便用户选择字段
动态报表的字频功能
• 1 设置字频过滤(仅保留字频为 -1 和字频>0的)
• 2 取消字频过滤,显示所有字段
• 3 重新计算字频并过滤 结果存入ZTBC_TABUSE表中
五
效果
通过下面两个截图比较, 可以发现, 通过字频统计并过滤的字段个数减少了很多.并且字频也给字段的使用提供了一个简单的依据.
(可以通过字频大概估算应用该字段后的动态报表呈现的条目数)
七
计算
字频的计算逻辑非常简单
• 对于表条目数>0的表
HANA底层表 PUBLIC.M_TABLES 中可以获取, 但特殊表比如MKPF/MSEG 在ABAP层面有条目数, 在HANA底层无条目数.
所以该条件不是必须条件
> 对于HANA底层表的访问详见链接 无峰,公众号:ABAP 技巧与实战 [ ABAP基础知识 怎么访问HANA数据库中的其它CATALOG的表
> ](https://mp.weixin.qq.com/s?__biz=Mzg4MjA1MjE4NQ==&mid=2247487740&idx=1&sn=06f69f335cdab7004e9db430d1d44f35&chksm=cf5dcdcaf82a44dcae6d181c2116b2c1f287c5126e176e3a1826183847933f091ca39f651749&token=220549748&lang=zh_CN#rd)
• 获取表的所有字段
• 对每个字段执行类似于下面的语句
SELECT SINGLE COUNT( DISTINCT bsart ) FROM ekko INTO -diffvalue.源代码附在文末, 有兴趣的可以参考一下.
八
总结
通过字频概念的引入, 动态报表进一步去除了无用的字段,简化了字段的勾选.让动态报表的使用更加 **得心应手** (
_小学语文老师评语:成语的灵活应用突出了重点_ ).
对于动态报表中新增的字段,设置字频为 -1
**约定**
如果你对这篇文章感兴趣,请帮忙点赞,在看,分享.
( **如果你真的喜欢这篇文章,请记得回来打个赏,作为支持我继续下去的动力,这是一个正反馈过程.
越多的人打赏,作者越有动力分享,读者就能享受更多的福利.毕竟打赏的金额富不了我,穷不了你,却能支持这个公众号长久发文.** )
syjf1976
sharry_xlp
Yannick_Duan
申请进入公众号讨论群提问或者参与话题讨论
字频统计源代码
*&---------------------------------------------------------------------**& Report ZBC_TABUSE*&---------------------------------------------------------------------**& 1. 通过系统表SELECT * FROM "PUBLIC"."M_TABLES" RECORD_COUNT 记录条目数 *TABLE_SIZE 记录表大小 获取存在数据的表 把该表映射到视图ZDDL_TABLES 使用*& 2. 通过DD03L统计表字段个数.*& 3. DD02L中的表才参与统计*& 4. 主键字段不参与统计*&---------------------------------------------------------------------*REPORT zbc_tabuse.
TABLES: ztbc_tabuse,ztbc_tabuse_log,dd02l,dd03l.
SELECT-OPTIONS: s_datum FOR ztbc_tabuse_log-crdat, s_tab FOR dd02l-tabname.PARAMETERS: p_fnum TYPE i. "字段个数,小于该字段个数的表不参与统计START-OF-SELECTION.
PERFORM frm_get_data.*&---------------------------------------------------------------------**& Form FRM_GET_DATA*&---------------------------------------------------------------------**& text*&---------------------------------------------------------------------**& --> p1 text*& <-- p2 text*&---------------------------------------------------------------------*FORM frm_get_data . "从底层表 PUBLIC.M_TABLES获取表的条目数:只获取条目数>0的表 DATA: lt_log LIKE HASHED TABLE OF zsbc_tabuse_log WITH UNIQUE KEY tabname. SELECT a~table_name AS tabname,a~record_count AS table_count,@sy-sysid AS sysid,c~zcount AS field_count FROM zcds_tables AS a INNER JOIN dd02l AS b ON b~tabname = a~table_name AND b~tabclass = 'TRANSP' AND b~as4local = 'A' AND b~as4vers = '0000' INNER JOIN zcds_dd03l_sum AS c ON c~tabname = a~table_name WHERE a~table_name IN @s_tab AND record_count > 0 AND schema_name = 'SAPHANADB' AND c~zcount >= @p_fnumINTO CORRESPONDING FIELDS OF TABLE @lt_log.
DATA: lt_save LIKE TABLE OF ztbc_tabuse. DATA: lt_log_save LIKE TABLE OF ztbc_tabuse_log, ls_log_save LIKE ztbc_tabuse_log. "获取所有需要统计的字段信息 SELECT a~tabname ,a~fieldname,a~inttype FROM dd03l AS a INNER JOIN @lt_log AS b ON b~tabname = a~tabname WHERE a~as4local = 'A' AND a~as4vers = '0000' AND a~precfield = ''"INCLUDE 结构 INTO CORRESPONDING FIELDS OF TABLE @lt_save.
* cl_demo_output=>display( lt_tables ). "循环表, 统计每个字段的情况,考虑性能,使用at new at end of SORT lt_save BY tabname. DATA: lv_select TYPE string, lv_select_s TYPE string, lv_table TYPE string, lv_value TYPE string. DATA: lv_used TYPE i. LOOP AT lt_save ASSIGNING FIELD-SYMBOL(<ls_save>) . AT NEW tabname. lv_table = <ls_save>-tabname. CLEAR lv_used. ENDAT. lv_select = |COUNT( DISTINCT { <ls_save>-fieldname } ) |. lv_select_s = <ls_save>-fieldname.* SELECT SINGLE COUNT( DISTINCT bsart ) FROM ekko INTO <ls_save>-diffvalue. SELECT SINGLE (lv_select) FROM (lv_table) INTO <ls_save>-diffvalue. IF <ls_save>-inttype = 'C' AND <ls_save>-diffvalue = 1. "对于文本字段, 判断如果是空值, 则设置 diffvalue = 0. 用于识别字段确实没有使用过* select single bsart into @data(lv_value) from ekko. SELECT SINGLE (lv_select_s) FROM (lv_table) INTO lv_value. IF lv_value IS INITIAL. <ls_save>-diffvalue = 0. ENDIF. ENDIF. IF <ls_save>-diffvalue > 1.
lv_used = lv_used + 1. ENDIF. AT END OF tabname. READ TABLE lt_log INTO DATA(ls_log) WITH TABLE KEY tabname = <ls_save>-tabname. IF sy-subrc = 0. MOVE-CORRESPONDING ls_log TO ls_log_save. ls_log_save-used_field_count = lv_used. CALL FUNCTION 'Z_BC_GET_ZSBC001' EXPORTING iv_updkz = 'I' CHANGING cs_data = ls_log_save. APPEND ls_log_save TO lt_log_save. ENDIF. ENDAT. ENDLOOP. IF lt_log_save IS NOT INITIAL. MODIFY ztbc_tabuse_log FROM TABLE lt_log_save. ENDIF. IF lt_save IS NOT INITIAL. MODIFY ztbc_tabuse FROM TABLE lt_save. ENDIF. COMMIT WORK AND WAIT.
ENDFORM.