资讯动态

027、内表概述与定义方式

发布时间:2026/8/19 10:11:17 来源:尧图企业网站定制
那天傍晚生产机上一个报表程序突然dump报的是ITAB_ILLEGAL_SORT客户电话打到我这。我看了一眼代码发现小伙子用SORT去排一个HASHED TABLE当场血压就上来了。ABAP里内表不是你想怎么排就怎么排的它的底层组织方式从定义那一刻就定死了。这个坑今天得好好说说。内表是个啥先别急着背概念ABAP里没有像C语言那种裸数组我们干活用的“动态数组”就是内表。它是一行一行的数据每行有相同的结构行数可以随便变内存由系统管。你从数据库取数、拼报表、做批导内表就是那个最常用的临时仓库。但你一旦定义错了类型后面SORT、READ、MODIFY全都会闹脾气。定义方式三兄弟脾气各不相同ABAP内表分三种标准表STANDARD、排序表SORTED、哈希表HASHED。别急我用大白话给你捋。标准表就是杂货铺数据按你插入的顺序排你想往里加就APPEND加完想排序就SORT一把。访问方式靠索引按行号或者关键字都行但默认线性查找数据多了慢吞吞。平时写报表、做临时数据90%用它够皮实。排序表有点像班里按成绩排好的座位表你往里插数据时系统自动按关键字排好。好处是读得快二分查找坏处是“别乱动”——你想用APPEND直接塞不行系统会拒绝。只能用INSERT或者COLLECT那种带合并的。还有它的排序关键字在定义时写死后面你想换个字段排序重新定义吧。哈希表更特殊它没有索引只允许按关键字访问。系统用哈希算法直接定位行查到一条数据快得飞起。但是它不能SORT不能按索引LOOP不能MODIFY除非用TABLE_LINE或者删了重插而且定义时必须指定一个UNIQUE KEY。那个生产机的dump就是有人SORT了哈希表活活把人家摇匀了。定义语句其实就那么几行我写给你看 标准表行类型用TYPES或者DATA定义的结构 DATA: lt_std TYPE STANDARD TABLE OF mara WITH NON-UNIQUE KEY matnr. 注意NON-UNIQUE标准表的关键字一般不强制唯一 排序表必须指定排序字段UNIQUE看需求 DATA: lt_srt TYPE SORTED TABLE OF mara WITH UNIQUE KEY matnr. 这里matnr是主键你要是敢往里面塞两条一样的直接硬错误 哈希表关键槽点是UNIQUE KEY是必须的没有它编译都过不去 DATA: lt_hsh TYPE HASHED TABLE OF mara WITH UNIQUE KEY matnr.你看其实就多了几个关键字。但“差之毫厘谬以千里”后面所有操作全看这个定义。行类型别只盯着TABLE OF定义内表除了表类型行类型也得讲究。行类型可以是结构体、数据库表、甚至另一个内表嵌套内表但尽量别用维护起来想骂人。常用写法 直接引用数据库表行结构就是整张表 DATA: lt_mara TYPE TABLE OF mara. 自定义结构做报表时更灵活 TYPES: BEGIN OF ty_line, matnr TYPE mara-matnr, maktx TYPE makt-maktx, menge TYPE p DECIMALS 3, END OF ty_line. DATA: lt_rep TYPE TABLE OF ty_line WITH EMPTY KEY.这里有个小坑早期有的系统不写WITH EMPTY KEY会报警告或者默认NON-UNIQUE KEY。如果你只是做个临时表不打算用关键字查询直接写TYPE TABLE OF ty_line也凑合但为了代码干净加个WITH EMPTY KEY更礼貌。初始化别把“清空”和“重置”搞混内表声明完了干活之前最好清一下。语法就两个CLEAR和REFRESH。CLEAR只清行内容保留内存大小REFRESH清空行也保留内存FREE则把内存也还给系统。平时循环填充前用REFRESH或者CLEAR都行但注意CLEAR对带表头行的内表会把表头也清掉老语法了现在不用表头行。我习惯用REFRESH lt_xxx语义明确。REFRESH lt_rep. 清空行保留内存 FREE lt_rep. 清空并释放内存下次用前得重新初始化你在循环里反复SELECT千万别把FREE放进去那性能直接崩。别问我怎么知道的。实操踩坑实录哈希表不能SORT回到最开头那个dump。业务逻辑是从物料主数据取一批料号然后去库存表查数量按数量排个序。小伙子图省事把库存数据读进了哈希表然后SORT lt_hsh BY menge DESCENDING。编译时居然没报错因为SORT语法本身是通用的到了运行时才知道你这个表不支持排序直接短转储。原因是哈希表的物理存储是无序的系统根本没法重排就像你没法给一袋豆子按大小排队——除非你一颗颗挑出来放进另一个容器。正确做法如果按数量排序先读哈希表或者标准表然后复制到一个标准表里再SORT。或者干脆一开始就用标准表读库存反正数量也不大。哈希表的优势是“按主键精确定位一条”如果你要全表排序千万别用它。再说说APPEND、INSERT、COLLECT的脾气标准表APPEND是加在最后INSERT可以指定位置COLLECT是合并相同关键字行的数值字段。排序表绝对不能APPEND只能用INSERT系统按关键字位置插入COLLECT也能用。哈希表只能用INSERT不能用APPEND也不能用MODIFY直接改关键字。 标准表追加正常 APPEND ls_data TO lt_std. 排序表这样写运行时必炸 APPEND ls_data TO lt_srt. 错误APPEND not allowed for sorted tables 哈希表也同理用INSERT才靠谱 INSERT ls_data INTO TABLE lt_hsh.COLLECT这玩意儿挺有意思做汇总特别香。比如你要统计每个物料的数量标准表直接COLLECT它自己找相同主键的行相加。但注意COLLECT的匹配依据是所有“非数值字段”不是你自己指定的某个字段。你要是心里没数很容易合错行。DATA: BEGIN OF ls_sum, matnr TYPE mara-matnr, menge TYPE p DECIMALS 3, END OF ls_sum. CLEAR ls_sum. ls_sum-matnr 100-100. ls_sum-menge 5. COLLECT ls_sum INTO lt_std. 如果已有100-100数量加5没有就新增一行什么时候选哪种表我的土办法你搞不清楚就记住三条数据量小几千行随便什么表标准表最省心。数据量大但按关键字精准读一行而且关键字唯一优先哈希表快得离谱。数据量大且范围查询比如按条件区间排序表好用因为本身排好了二分查找很舒服。但现实是大多数报表都是读取、循环、再查找。这时候标准表二次排序也够用。ABAP性能瓶颈常出现在嵌套LOOP里你用一个标准表在LOOP里READ TABLE ... WITH KEY那是O(n*m)的灾难。正确姿势是把内表按查找关键字排序或者定义成排序表用二分查找。 反面教材内层READ一遍遍扫慢到怀疑人生 LOOP AT lt_header INTO ls_header. READ TABLE lt_item INTO ls_item WITH KEY vbeln ls_header-vbeln. ENDLOOP. 正面写法要么把lt_item定义成排序表要么先SORT再读 SORT lt_item BY vbeln. LOOP AT lt_header INTO ls_header. READ TABLE lt_item INTO ls_item WITH KEY vbeln ls_header-vbeln BINARY SEARCH. ENDLOOP.内表操作的“隐形规则”赋值、比较、传递内表可以整表赋值lt_std2 lt_std1这是复制一份独立内存不是指针。这一点和Java、Python不一样别想着“引用传递”。所以在方法里传内表除非用CHANGING或EXPORTING否则修改不会传回调用方。有时候你调试半天看着方法里改了外面没变八成是忘了用CHANGING。比较内表可以用、语法上支持但实际很少用得逐行比较效率不高。关于表头和隐式工作区这代年轻人可能没见过的坑老ABAP支持带表头的内表DATA: BEGIN OF ITAB OCCURS 0.这种现在早被抛弃了。但有些烂代码还留着里面到处都是ITAB-matnr这种写法可读性极差还容易出“隐式工作区”的错。你记住新代码一定用DATA(ls_data) VALUE #( ... )或者显式工作区别用LOOP AT lt INTO lt这种自残操作。实战建议定义方式要和后续操作一起想别到写代码时随手选一种内表后面一调就是半小时。正确姿势是先想清楚数据的读取方式。如果只做一次FULL SCAN标准表够了如果多次按KEY读排序表或哈希表选一个如果还要排序输出标准表最后SORT。我自己写ABAP的惯性是从数据库SELECT出来一律进标准表因为SELECT本身是按主键顺序或索引的标准表不会额外消耗。需要多次READ先SORT BINARY SEARCH或者如果表不大直接定义成SORTED。只需要按主键查一条且数据量巨大比如几十万用HASHED但一定想清楚别去SORT它。要合并汇总用COLLECT但先确认非数字字段的匹配规则是你想要的。每次LOOP之前想一下是否需要使用WHERE条件而不是把全表读进来再过滤。还有一点ABAP新语法VALUE和NEW可以快速初始化内表比如DATA(lt_out) VALUE string_table( ( Hello ) ( World ) ).这比先声明再一行行APPEND清爽多了。但新语法也有坑它默认生成的是标准表如果你要排序表的初始化得显式写VALUE sorted_table_type( ... )。最后丢几句经验之谈内表定义是ABAP的“地基”地基歪了上面盖什么都是危房。我见过太多案例一行TYPE TABLE OF后面不写表类型默认标准表然后性能问题一堆。还有那种WITH HEADER LINE的老代码维护起来真的头大。新手如果没人带建议多去看SAP标准功能的代码看人家怎么定义内表——ST05跟踪一下或者直接打SE11看表结构别自己瞎造轮子。如果你今天只记一句话标准表是万金油排序表是纪律委员哈希表是特种兵。用哪个取决于你要“按顺序存取”、“自动有序”还是“精准秒查”。别把特种兵当搬运工使。好了这个dump其实改三行就完了——把哈希表定义改成标准表再SORT。修完之后客户说了句“你们ABAP真麻烦”我只笑笑。代码世界里规矩就是自由。该回去处理下一个case了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价