1、背景
定制开发功能运维,阅读发现如下代码:
SELECT A~VBELN,
A~POSNR,
A~MATNR,
A~ABGRU,
C~MAKTX,
A~KWMENG,
A~ZCTY, "增强字段
A~ZJSY, "增强字段
A~ZZGY, "增强字段
A~VRKME,
A~CMTD_DELIV_DATE AS MBDAT,
A~WERKS,
A~LGORT,
B~BSTKD, "客户参考
B~BSTKD_E , "项目号
D~BESKZ,
D~SOBSL,
D~PLIFZ,
D~DZEIT,
D~WEBAZ
FROM VBAP AS A
LEFT JOIN VBKD AS B ON A~VBELN = B~VBELN AND A~POSNR = B~POSNR
LEFT JOIN MAKT AS C ON A~MATNR = C~MATNR AND C~SPRAS = '1'
LEFT JOIN MARC AS D ON A~MATNR = D~MATNR AND A~WERKS = D~WERKS
WHERE A~WERKS IN @S_WERKS
AND B~BSTKD IN @S_BSTKD
AND B~BSTKD_E IN @S_BSTKE
AND A~ABGRU NE 'Z3'
INTO CORRESPONDING FIELDS OF TABLE @GT_SOHEAD.
SELECT A~VBELN,
A~POSNR,
A~MATNR,
A~ABGRU,
C~MAKTX,
A~KWMENG,
A~ZCTY, "增强字段
A~ZJSY, "增强字段
A~ZZGY, "增强字段
A~VRKME,
A~CMTD_DELIV_DATE AS MBDAT,
A~WERKS,
A~LGORT,
B~BSTKD, "客户参考
B~BSTKD_E, "项目号
D~BESKZ,
D~SOBSL,
D~PLIFZ,
D~DZEIT,
D~WEBAZ
FROM VBAP AS A
LEFT JOIN VBKD AS B ON A~VBELN = B~VBELN
LEFT JOIN MAKT AS C ON A~MATNR = C~MATNR AND C~SPRAS = '1'
LEFT JOIN MARC AS D ON A~MATNR = D~MATNR AND A~WERKS = D~WERKS
WHERE A~WERKS IN @S_WERKS
AND B~BSTKD IN @S_BSTKD
AND B~BSTKD_E IN @S_BSTKE
AND B~POSNR = '0000'
AND A~ABGRU NE 'Z3'
INTO CORRESPONDING FIELDS OF TABLE @GT_SOHEAD1.
LOOP AT GT_SOHEAD1.
APPEND GT_SOHEAD1 TO GT_SOHEAD.
ENDLOOP.
LOOP AT GT_SOHEAD.
GT_SOHEAD-ZNUMB = GT_SOHEAD-KWMENG + GT_SOHEAD-ZCTY + GT_SOHEAD-ZJSY + GT_SOHEAD-ZZGY.
MODIFY GT_SOHEAD.
ENDLOOP.
SORT GT_SOHEAD BY VBELN POSNR ASCENDING BSTKD_E DESCENDING.
DELETE ADJACENT DUPLICATES FROM GT_SOHEAD COMPARING VBELN POSNR.
分析理解其SQL的意图,最关键的是要理解VBKD表的逻辑。
(1)数据表 VBAP 和 VBKD
咋看关键字一致,很容易认为通过 VBAP~VBELN = VBKD~VBELN AND VBAP~POSNR =VBKD~POSNR 匹配即可,所以会对第二个SELECT难以理解。
(2)业务数据分析
通过实测,发现针对同一个销售凭证,存在如下数据情况:
VBAP表:三个行项目
VBKD表:三个行项目,但是与VBAP的行项目不对应
分析业务操作:'000030’行是在原销售凭证上新追加的一行(追加后未对该行做修改操作)
(3)关于VBKD表
通过业务分析和查询资料了解,VBKD表中的’000000’行为表头公共信息,VBKD表中的非’000000’行为对应VBAP项目信息,并且是在VBAP首次新增后,进行了修改才会产生对应的VBKD行项目记录。
(4)SQL的意图
通过以上分析,大概可以理解为,通过第一个select查询主要记录,通过第二个select来补充缺对应vbkd项目号的记录,然后合并两者记录,再去重。
(5)代码调试验证
其中
GT_SOHEAD[]获取到 ‘000010’、‘000020’ 两行数据,
GT_SOHEAD1[]获取到 ‘000010’、‘000020’ 、‘000030’ 三行数据,
两个LOOP之后
GT_SOHEAD[]获取到5行数据,
去重之后,GT_SOHEAD[]才真正获取到期望的3行数据
(6)总结
通过调试分析,显而易见,这个取数逻辑是非常不合理,存在大部分的冗余无效操作。
2、优化方案
通过以上分析和调试,针对上述取数逻辑,甚至可以直接采用第二个SELECT来取数。
但考虑到VBAP和VBKD关联取数的普适性,调整代码如下:
SELECT A~VBELN,
A~POSNR,
A~MATNR,
A~ABGRU, " 销售凭证的拒绝原因
C~MAKTX, " 物料描述
A~KWMENG, " 销售数量
A~ZCTY, " 增强字段
A~ZJSY, " 增强字段
A~ZZGY, " 增强字段
A~KWMENG + CAST( A~ZCTY AS INT2 ) + CAST( A~ZJSY AS INT2 ) + CAST( A~ZZGY AS INT2 ) AS ZNUMB, " 汇总数
A~VRKME, " 销售单位
A~CMTD_DELIV_DATE AS MBDAT, "交货日期
A~WERKS,
A~LGORT,
COALESCE( B~BSTKD, E~BSTKD ) AS BSTKD, " 客户参考
COALESCE( B~BSTKD_E, E~BSTKD_E ) AS BSTKD_E, " 项目号
D~BESKZ, " 采购类型
D~SOBSL, " 特殊采购类型
D~PLIFZ, " 计划交期
D~DZEIT, " 生产周期
D~WEBAZ " 收货处理天数(质检天数)
FROM VBAP AS A
LEFT JOIN VBKD AS B ON A~VBELN = B~VBELN AND A~POSNR = B~POSNR
" VBAP行项目未修改时无对应行的VBKD行,需要取0行
LEFT JOIN VBKD AS E ON E~VBELN = A~VBELN AND E~POSNR = '000000'
LEFT JOIN MAKT AS C ON A~MATNR = C~MATNR AND C~SPRAS = '1'
LEFT JOIN MARC AS D ON A~MATNR = D~MATNR AND A~WERKS = D~WERKS
WHERE A~WERKS IN @S_WERKS
AND COALESCE( B~BSTKD, E~BSTKD ) IN @S_BSTKD " SO客户参考
AND COALESCE( B~BSTKD_E, E~BSTKD_E ) IN @S_BSTKE " SO项目号
AND A~ABGRU <> 'Z3' " Z3-订单关闭,PP停
ORDER BY A~VBELN ASCENDING, A~POSNR ASCENDING, B~BSTKD_E DESCENDING
INTO TABLE @GT_SOHEAD.