034、内表嵌套与结构内表

📅 2026/8/20 11:44:41
034、内表嵌套与结构内表
034、内表嵌套与结构内表那天同事拉着我过去说程序跑出来没数据明明内表在第一遍循环里还看得见东西。我打开调试器一眼瞅中那个字段的类型栏写着“Table”。刚开始学ABAP的人八成没见过这种场面——点击这个字段里头居然又冒出一张表。他愣了“这啥表套表”我说这就是内表嵌套ABAP里最容易被新手当成“结构体数组”但其实比那多一层的东西。先讲清楚什么叫“结构内表”。内表的每一行如果是一个结构那这张表就是结构内表。比如你定义一个人名字、年龄然后说“给我一张放很多人的表”这就是最普通的内表。TYPES: BEGIN OF t_person, name TYPE string, age TYPE i, END OF t_person. DATA: gt_people TYPE TABLE OF t_person.这种表平铺直叙字段一目了然调试的时候不会出幺蛾子。可问题来了——现实业务里经常有父子关系比如一个订单抬头是订单号、日期底下还挂着多个物料行项目。你要是用两张平铺内表就得自己在代码里维护订单号与行项目的对应关系。更麻烦的是从RFC或JSON接口拿到数据时数据本身就是嵌套的你非把它拆平反而更痛苦。ABAP允许你定义“内表行里还带内表”这就是内表嵌套。具体写法看下面。* 先定义行项目结构再定义行项目表 TYPES: BEGIN OF t_item, matnr TYPE matnr, quantity TYPE i, END OF t_item. TYPES: tt_item TYPE TABLE OF t_item. * 订单抬头结构里放一个内表字段 TYPES: BEGIN OF t_order, order_no TYPE vbeln, date TYPE sy-datum, items TYPE tt_item, 这就是嵌套注意别把它写成TABLE OF END OF t_order. DATA: gt_orders TYPE TABLE OF t_order.注意结构里的items类型是tt_item不是TABLE OF。这里很多人写错过差点把结构定义成内表的表然后编译器直接报错。这里踩过坑牢记。给这种嵌套表赋值得一层一层来。先给行项目工作区APPEND到外层工作区的内表字段里最后再把整个外层工作区APPEND到外层表。DATA: ls_order TYPE t_order, ls_item TYPE t_item. ls_order-order_no 1000. ls_order-date sy-datum. ls_item-matnr MAT-01. ls_item-quantity 5. APPEND ls_item TO ls_order-items. 先往内层塞 ls_item-matnr MAT-02. ls_item-quantity 3. APPEND ls_item TO ls_order-items. APPEND ls_order TO gt_orders. 外层再塞看明白没有ls_order-items本身就是一张内表你不能直接ls_order-items xxx得拿行项目工作区去APPEND。这跟操作普通内表一模一样只不过这个内表现在住在结构字段里。访问嵌套数据也一样双层LOOP。这里我推荐用字段符号别把整个结构往工作区里搬否则内表字段会连累一大片数据做深层复制性能吃不消。DATA: ls_item TYPE t_item. FIELD-SYMBOLS: fs_order TYPE t_order. READ TABLE gt_orders ASSIGNING fs_order WITH KEY order_no 1000. IF sy-subrc 0. LOOP AT fs_order-items INTO ls_item. WRITE: / ls_item-matnr, ls_item-quantity. ENDLOOP. ENDIF.ASSIGNING比INTO省了一次深层拷贝。深层拷贝这个词可能吓人但反过来想如果一笔订单下有几百个行项目你把整个ls_order从gt_orders里READ INTO出来等于把这几百行又复制了一遍。在循环里这么搞内存会疯的。这里踩过坑别这样写。还有个大坑跟“清空”有关。你用CLEAR ls_order时ABAP会把内表字段items一并清空这点还好。但如果你在循环里重复利用ls_order忘记CLEAR上一次残留的行项目会留在items里下一笔订单会莫名带上旧数据。我亲眼见过有人为了这问题查了一整天最后发现是CLEAR少写了一行。那嵌套内表到底能干嘛最实在的用处是描述层级结构。比如对接外部系统的JSON数据长这个样子{orderNo:1000,date:2025-03-01,items:[{matnr:MAT-01,quantity:5},{matnr:MAT-02,quantity:3}]}在ABAP里用嵌套内表来接收这种结构简直无缝衔接。ABAP的JSON转换工具会直接把内表字段映射成JSON数组。你要是用两张平铺表反而要自己拼结构、对ID麻烦得多。但嵌套内表也有不好使的时候。ALV表格控件默认不支持嵌套显示。你试图把一个含内表字段的内表直接塞给ALV它只会显示一个“Table”字符串或干脆报错。做报表时老老实实把嵌套展平成一张宽表把抬头字段重复到每一行才是正道。所以我的习惯是接口解析、内存里做复杂业务处理用嵌套展示、打印、下载一定转平铺。另外别对嵌套内表使用SORT或DELETE ADJACENT DUPLICATES之类的操作。内表字段没法比较大小也不能做唯一性判断编译器可能直接拒绝。就算标准表让你塞进去了运行时结果也是不可预测的。这里踩过坑别去挑战ABAP的脾气。还有一点嵌套内表的赋值比想象中“贵”。如果你真的需要复制一个嵌套内表MOVE或会深拷贝所有内嵌的数据。数据量大时这一行代码能让你程序卡上好几秒。如果仅仅是想传引用用字段符号或ASSIGN甚至考虑动态指针。不过ABAP里没有真正意义的指针字段符号就是你的好兄弟。最后说一个调和“结构内表”这词。有些人把“结构内表”理解为“结构里有内表字段”也就是我上面讲的订单结构也有人把“结构内表”理解为“行类型是结构的内表”也就是最普通的gt_people。这两种叫法容易让人晕。我在团队里统一这么说gt_people叫“标准内表”或“平铺内表”带内表字段的t_order叫“深层结构”或“嵌套内表”。你写代码时定义清楚术语别人读你的文章或代码才不容易懵。那就这样。学ABAP不用追求花哨嵌套内表是个工具不是玩具。我的经验是能用SQL JOIN解决的别在内存里折腾嵌套必须得用嵌套的时候牢牢记住三层循环的节奏还有字段符号这个性能救星。调试器里再看到“Table”类型双击进去里面藏着另一个世界。你要做的是先搞清楚那一层世界的边界别一脚踩空。