ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

059、JOIN内联合查询

059、JOIN内联合查询 今天早上用户那边报了个报表数据不对物料清单里有个物料明明有基本数据但报表里死活查不到。我第一反应是权限问题查了一圈不是。后来翻代码发现是个JOIN写得太“干净”了——内连接两表匹配才返回。那个物料在主数据表里有记录但在文本表里没维护当前语言的文本直接就被滤掉了。用户一看结果“少数据”自然觉得是bug。这就是JOIN的脾气内联合只认匹配。先把这个JOIN内连接的东西掰开揉碎。ABAP里写内联合最常用的就是SELECT ... FROM 左表 INNER JOIN 右表 ON ...。这里的INNER JOIN就是“两表都有货才要”缺一边都不行。看这段写法SELECT a~matnr a~maktx b~meins FROM makt AS a INNER JOIN mara AS b ON b~matnr a~matnr WHERE a~spras sy-langu INTO TABLE DATA(lt_result).逻辑上是从makt物料文本表里拿文本再从mara物料主数据表里拿单位。这里面坑就来了——ON条件里只有物料号没带客户端MANDT。别看系统有时候会自动补客户端条件但你一旦自己写了ON那个“自动补”就不一定那么听话了。我就在这踩过雷上线后查出来的数据混进了别的客户端还好是测试环境不然真没法收场。稳妥点把客户端字段也写上SELECT a~matnr a~maktx b~meins FROM makt AS a INNER JOIN mara AS b ON b~matnr a~matnr AND b~mandt a~mandt WHERE a~spras sy-langu INTO TABLE DATA(lt_result).别嫌啰嗦这算ABAP OPEN SQL的祖传手艺。客户端条件能显式写就显式写至少出了事你能背锅背得明白。再说说字段选择。两个表都有MANDT、MATNR这类字段SELECT后面不带表别名的话系统直接给你个语法错误或者更阴险地取到同一个字段的值你查半天不知道咋回事。所以别名是必须的上面代码里a~、b~就是干这个的。如果字段名不冲突你俩表里都叫NAME但含义不一样那就真得靠别名区分。还有个容易忽视的点内连接的结果数量受到ON条件影响最大。行数对不上先别怀疑数据有问题仔细看这两表关联字段是不是一对多。比如一个物料有多条文本多种语言你JOIN上mara后每一条文本都会和mara那一行拼一遍结果自然膨胀。反过来mara表里一条物料makt表里没这个语言那就是开头说的连条数据都不给你。内连接就是这么轴它不管你是不是“主数据在就行”它的原则是两边都得找到匹配的行。实际项目里有些人为了省事把内连接放在FOR ALL ENTRIES里绕弯子。比如先查内表A再用FOR ALL ENTRIES去查B。这种做法不是不行但容易踩两个坑一是内表为空时FOR ALL ENTRIES会忽略条件直接全表扫——这个真有人血亏二是FOR ALL ENTRIES生成的SQL会自动过滤掉重复记录有时候你本来不想去重结果数据默默少了。所以能用JOIN解决的别花里胡哨搞FOR ALL ENTRIES。JOIN的语义清晰效率也高得多。再聊个性能上的老生常谈。ON条件后面别写函数比如ON b~matnr a~matnr AND b~er_dat ...你要是给字段套了RPAD、SUBSTRING那数据库索引直接废了。咱ABAP跑在数据库上头这种SQL语句优化器也救不了你。真想对字段做转换先取出数据再用程序逻辑处理别把脏活累活甩给JOIN。还有一点内连接的表顺序也有讲究。一般把数据量小的放前面或者把过滤条件强的放前面让数据库先圈定小范围。但现实里ABAP的OPEN SQL最终会交给数据库优化器表顺序不一定影响执行计划。我个人习惯还是按业务主角放前面。比如上面例子makt是业务入口我查的是文本就把makt放前面看着顺眼逻辑上也说得通。后来那个report我改成了LEFT OUTER JOIN把makt表的条件挪到WHERE里问题就没了。但今天这节的题目是内连接就不展开外面连接了。记住内连接是“交集”只有匹配才能见天日。如果你做的是主数据扩展属性的组合内连接很容易把那些“只有主数据没扩展”的边角料扔了这时候你得问业务是“有都显示”还是“匹配才显示”。最后给点我自己的经验。写JOIN别急着跑先把两张表的关联关系画一下是1:1、1:N还是N:1然后心里有个预期结果行数。写完后用ST05看执行计划确认没全表扫。最重要的是MANDT条件必须写上别名必须写清SELECT字段别用*除非你只要调试时用一次。这些习惯养成后你写的ABAP代码基本不会因为JOIN被人找上门。调试这事十个有八个是JOIN条件不对。剩下的两个一个是没注意内连接会丢不匹配的数据另一个就是忘了客户端。今天这篇算把内连接的老底都揭了。你照着写不亏。
返回列表