尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

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

057、ORDER BY、GROUP BY

057、ORDER BY、GROUP BY 057、ORDER BY、GROUP BY那天半夜被电话叫醒说某个报表数据对不上拉出来一看明细金额和汇总金额差了一截。我第一反应是GROUP BY写错了结果打开程序发现SELECT语句里既没有ORDER BY也没有GROUP BY就一个单纯的FOR ALL ENTRIES加SUM。再往下看原来同事在循环里自己手工累加累加逻辑里还有一个CLEAR放在不对的位置。这种问题见得多了其实很多ABAP新手甚至老手对ORDER BY和GROUP BY的理解都停留在“排序”和“分组”的表面真正在数据库层面发生了什么没太较真。今天借这个事把这两个关键字掰开揉碎聊聊。先接上刚才那个报表。那个程序最后改成一句标准SQL搞定SELECT matnr, SUM(menge) FROM vbap GROUP BY matnr。为什么要用GROUP BY因为你根本不需要明细行你只需要每个物料的总数量。如果非要在ABAP里循环累加那等于把数据库该干的活搬到应用服务器上干数据量大一点内存和CPU都在哭而且还要自己处理分组边界、清空累加变量、排序一致性……一不小心就是这种半夜电话。顺便说一句ORDER BY和GROUP BY经常被摆在一起但它们的职责完全不同。ORDER BY是控制结果集的行顺序GROUP BY是控制结果集的行聚合。你完全可以只GROUP BY不ORDER BY结果顺序是不保证的实际上数据库返回的行序取决于执行计划、索引、并行度等等。很多ABAP初学者以为GROUP BY之后自带排序那是错觉。如果你需要输出顺序永远显式加上ORDER BY。举一个典型场景你要查每个客户的订单总金额想按金额从大到小排。很多人会这样写SELECT kunnr, SUM(netwr) FROM vbak GROUP BY kunnr ORDER BY sum(netwr) DESCENDING。这在语法上没问题但注意ORDER BY后面跟的是聚合表达式不是原始字段。有些ABAP版本或者数据库可能对别名比较友好你可以先给SUM(netwr)起个别名比如AS total然后ORDER BY total。不过我建议在ABAP里尽量不用数据库别名来做ORDER BY因为ABAP Open SQL的解析在某些老版本上对别名处理比较拧巴你明明在SELECT里定义了别名ORDER BY却报“未知字段”。这不是你写错了是ABAP的语法限制。稳妥做法直接用SUM(netwr)写一遍或者全部取到内表后在ABAP层面用SORT。说到内表排序很多人会问那我干脆不用ORDER BY取回来自己SORT不行吗当然行但你要明白代价。如果数据量是几千行无所谓。如果是几十万行你把所有明细行都拉到应用层再排序那网络传输时间、应用服务器内存占用都上去了。而ORDER BY在数据库端由索引或排序算子完成通常更高效。但注意“通常”如果你ORDER BY的字段上没有索引数据库也要做一次显式排序这时候不一定比取回来SORT快多少但至少省了网络传输。所以原则是能下推到数据库的操作就不要自己写循环。讲了ORDER BY重点说GROUP BY。GROUP BY的本质上就是把一张大表按某些字段的值拆成一个个桶每个桶内做聚合。你要理解一个铁律SELECT列表中出现的普通字段必须全部出现在GROUP BY里。这不是ABAP的规则这是SQL标准。但ABAP Open SQL有个让人头疼的扩展如果某字段在GROUP BY中没出现但你在SELECT里选了它并且用的是“所有字段”或者“复合结构”ABAP可能不会报错而是取桶内“任意一行”的值——这简直是蓄意埋雷。我记得SAP的文档里明确说这样取值是不确定的。换句话说你分组后想再取某个非分组字段结果不可预知。有人觉得“反正这些行的物料号都一样随便取一个不就行了”但数据库不会保证你取到的是哪一行可能今天取到第一行明天取到最后一行一旦并行执行结果还能变。所以别赌这个。真正的坑在ABAP的GROUP BY和SUM的组合。我见过有人写SELECT matnr, werks, SUM(menge) FROM mseg GROUP BY matnr。他以为只按物料分组然后顺便把工厂也选出来。但SQL语义是你GROUP BY matnr那么结果集里每个物料只有一行werks是哪个工厂如果一条物料有多个工厂数据库返回哪个工厂不确定。ABAP不会拦你但运行结果会偷偷出错。正确写法是GROUP BY matnr, werks这样才是每个物料在每个工厂的汇总。这真的是经典错误我在代码评审里见过不下十次。再来说说HAVING。HAVING是跟GROUP BY配套的用来过滤分组后的结果。很多人想当然用WHERE去过滤聚合后的值比如“筛选订单总额大于1000的客户”。WHERE是在分组之前执行的行级过滤它根本看不到SUM(netwr)这种聚合结果。你写WHERE sum(netwr) 1000数据库直接报错因为WHERE阶段聚合还没发生。这时候要用HAVING SUM(netwr) 1000。ABAP的HAVING语法和标准SQL几乎一样但要注意在其中引用字段时你可以写原始字段或聚合函数但不能引用SELECT里的别名这跟ORDER BY的坑类似。还有一种容易踩的GROUP BY和FOR ALL ENTRIES联用。FOR ALL ENTRIES本身会生成一个特殊的IN条件它在Open SQL中会做许多隐式处理比如去重、空表跳过等。你把GROUP BY加在带FOR ALL ENTRIES的语句中语法能过但实际执行时数据库可能生成复杂的连接条件性能下降很厉害。更隐晦的是FOR ALL ENTRIES会使得数据库优化器对GROUP BY的并行/分组策略变得保守有时明明可以走hash聚合结果却做了排序聚合内存一爆就是dump。所以我的习惯是遇到大表FOR ALL ENTRIES先别急着汇总把范围条件压到最小先用GROUP BY把聚合结果放内表再跟FOR ALL ENTRIES的结果做二次处理。或者直接用JOIN但那是另一个话题。再说说一个实战细节GROUP BY的顺序和字段顺序有关吗比如GROUP BY matnr, werks和GROUP BY werks, matnr结果集的行内容完全一样只是列顺序不同。如果你SELECT用的是字段列表那列顺序由SELECT决定跟GROUP BY无关。但如果你用SELECT *那结果集的列顺序按照表定义来GROUP BY的顺序不影响。然而在ABAP中GROUP BY后面字段的书写顺序却可能影响数据库索引的使用。如果表上有复合索引(matnr, werks)你写成GROUP BY werks, matnr数据库可能无法有效利用索引前缀导致全表扫描。所以在写GROUP BY时尽量把字段顺序调整成与索引一致。这属于优化层面但很实用。关于ORDER BY还有一个容易混淆的ABAP内表SORT和数据库ORDER BY的排序规则不一致。数据库排序用的是数据库的字符集和排序规则比如Oracle里默认二进制排序而ABAP的SORT用的是ABAP的排序规则可能带locale、大小写不敏感等。你在查询里ORDER BY拿到的是数据库排好序的然后你把结果放到内表再用ABAP的SORT排序如果排序规则不同顺序可能会发生变化。这个坑很冷但一旦碰上你会觉得见鬼。比如数据库按ASCII排大写字母在小写字母前面而ABAP的SORT在德语环境可能把小写字母排在大写前面。所以同一个内表你查询时ORDER BY一次然后代码里又SORT一次结果顺序很可能不是你想要的。我建议只信任一层排序逻辑要么数据库排要么应用层排别混着来。再讲一个我在调试中遇到的诡异问题GROUP BY之后用ORDER BY结果排序没生效。看代码SELECT matnr SUM(menge) FROM vbap GROUP BY matnr ORDER BY matnr。语法没毛病但运行出来顺序还是乱的。最后发现这个查询加了UP TO 100 ROWS本来想取前100个物料可ORDER BY在数据库优化器眼里不是强制性的当它认为排序没必要或者有并行扫描时可能会忽略某些排序请求特别是在GROUP BY聚合后。这听起来不可思议但确实在某些版本和某些数据库上发生。解决办法先取聚合结果到内表再用ABAP SORT排序然后取前100行。或者把这个查询包装成子查询SELECT * FROM (SELECT matnr, SUM(menge) FROM vbap GROUP BY matnr ORDER BY matnr) WHERE rownum 100。但在ABAP Open SQL里写子查询需要数据库方言支持不同数据库语法不通用。所以在ABAP里如果你要“分组排序数量限制”我强烈建议先GROUP BY取回内表再SORT再截取。别嫌多一次数据搬移稳定性比性能重要。还有一个高频错误SELECT字段列表里既有分组字段又有非聚合非分组字段然后ORDER BY里引用了非分组字段。前面说了这个字段的值是不确定的按不确定的值排序相当于随机排序。比如GROUP BY matnr然后SELECT matnr, werksORDER BY werks。werks可能是桶内任意一行的值今天可能取A工厂明天取B工厂排序结果自然就变了。如果你真需要“每个物料汇总然后按某个工厂维度排序”那你的分组字段就应该是matnr, werks否则逻辑不自洽。GROUP BY另一个高级坑是“分组后拼接字符串”。ABAP没有GROUP_CONCAT这种内置函数老版本没有新版本我看到SAP提供了STRING_AGG但可能只在S/4HANA的某些版本支持。如果你还在ECC想实现“每个物料对应多个工厂拼接成字符串”只能在ABAP里循环。但很多人非要挑战语法用函数WRF_CHAR_STRING_SPLIT什么的不靠谱。我一般做法是先按物料、工厂查出来然后ABAP循环用一个哈希内表按物料累加字符串。这虽然没有SQL直观但完全可控。而如果你用了SNWD等新数据模型支持STRING_AGG也别高兴太早注意它按什么分隔以及处理NULL的方式。讲一个真实的性能优化案例。我们有张表ZORDIT存储订单行项目大概几千万行。业务要做一个日汇总统计每个物料每天的订单数量。最初的代码是SELECT全部行循环累加跑一个多小时。我改成SELECT matnr, erdat, SUM(menge)FROM ZORDITGROUP BY matnr, erdatINTO CORRESPONDING FIELDS OF TABLE lt_sum.加上ORDER BY matnr erdat。整个查询不到半分钟。为什么快数据库端只返回分组汇总结果几百行而已网络传输小数据库的hash聚合也比逐行处理强太多。而且ORDER BY能利用索引如果索引是matnrerdat。这让我想起一句老话能用一条SQL解决的绝不用循环。但注意这条SQL在HANA上没问题在Oracle上如果表分区键是erdat那么GROUP BY顺序最好写成erdat, matnr以利用分区裁剪。所以你看GROUP BY字段顺序没有绝对对错要结合底层存储。现在说说我个人的经验习惯。首先我不喜欢在Open SQL里用聚合函数加别名特别在GROUP BY中别名容易引发后续ORDER BY或HAVING的歧义。其次我写GROUP BY时会把所有非聚合字段都列进去宁可多分组也不留不确定值。第三我用ORDER BY时尽量用简洁的字段名不用表达式尤其是CASE WHEN这类数据库性能差不说在HANA上还可能限制并行。如果你真的需要复杂排序逻辑我倾向于在ABAP内表SORT时用STABLE选项确保相同键的行保持原顺序。不过STABLE只对内表SORT有效对数据库ORDER BY没有意义。对了还有一个细节ABAP Open SQL里的ORDER BY用法是DESENDING、ASCENDING不是SQL标准里的DESC、ASC。这个拼写有人老搞错。全称写上去就行。另外按多个字段排序时每个字段后面都要跟着方向比如ORDER BY matnr ASCENDING, erdat DESCENDING这是ABAP的语法要求。如果你漏了方向默认升序容易跟你想的降序混。还有一个奇葩情况GROUP BY一张空表。如果表里没有数据GROUP BY结果集是空内表这没问题。但如果你用了SUM(字段)而没有任何行SUM返回NULL。ABAP的SUM在Open SQL中如果所有行都不存在或者字段都是NULL结果可能是初始值也可能是空取决于字段类型和数据库。为避免NULL传到内表引起后续运算错误我习惯在SELECT里用COALESCE(SUM(menge), 0)来处理。但COALESCE在ABAP Open SQL中有的版本不支持。老办法是读回内表后在ABAP循环里判断字段是否为初始值或者用数据库的NVL。HANA支持COALESCEOracle也支持。但为了兼容性我通常在ABAP层面再补一个IF。上次调试那个问题最后发现还有一个隐藏陷阱GROUP BY和ORDER BY一起用时ORDER BY字段必须出现在SELECT列表中其实不一定在标准SQL里ORDER BY可以引用不在SELECT里的字段只要这个字段属于该表并且不影响分组语义。但ABAP Open SQL有个限制ORDER BY后面只能使用SELECT列表中的字段名。如果你ORDER BY一个不在SELECT里的字段语法检查就直接报错。这个限制跟标准SQL不同坑了不少从其他SQL转来的人。解决方法是把那个字段也加进SELECT列表但这样你必须把它加进GROUP BY否则就会导致结果集行数变多和你原意违背。所以唯一合理办法是把该字段作为分组条件或者重新设计查询。这个限制迫使你明确“排序依据”和“分组粒度”之间的关系其实是好事。再深入一下GROUP BY的结果集能不能和原始表做关联比如你GROUP BY matnr得到每个物料总数量然后想通过SELECT也取出物料描述。你可以在同一SELECT里用JOIN关联MARA表关联条件是MARA-MATNR vbap-MATNR。但要注意不能把MARA的字段直接加进SELECT而不同时加进GROUP BY。举个例子SELECT v~matnr, m~maktx, SUM(v~menge)FROM vbap AS vINNER JOIN makt AS m ON m~matnr v~matnrGROUP BY v~matnr, m~maktx这里把maktx加进GROUP BY才合法。因为maktx和matnr是一对一关系在特定语言下这样分组粒度不会变。但如果你在JOIN中因为语言条件产生了多行比如makt有多个语言那分组粒度就会膨胀结果出错。所以用JOIN时先确认JOIN是否保持了唯一性。这个一旦疏忽就是数据质量事故。我见过一个很隐蔽的写法GROUP BY不是字段而是字段的表达式比如SUBSTRING(erdat,1,6)按月分组。这在标准SQL里没问题但ABAP Open SQL支持有限而且用表达式分组后SELECT里也必须用相同表达式ORDER BY也一样否则语法或结果不一致。更让我头疼的是有些数据库允许GROUP BY表达式但ABAP的语法检查器在代码生成时不一定会正确传给底层。我建议这类需求不要试图用Open SQL搞定干脆取全天下到ABAP内表然后分组循环。或者如果你用的是HANA可以考虑写AMDP用原生SQL的TO_CHAR/SUBSTR来做那才是正经路子。AMDP其实是另一个话题但很多复杂分组用AMDP顺手很多。写这篇文章时我又想起一个让无数人挠头的问题GROUP BY后结果行数是多少很多新手以为GROUP BY只生成几行实际它生成的组数等于“分组字段的唯一组合数”。如果分组字段是物料工厂那么结果大约等于物料工厂组合数。但如果你在SELECT里同时选了物料描述并且把物料描述也加入GROUP BY而物料描述字段有个“前导空格”或者大小写不一致那它不会被视为同一组结果行数会多出很多。比如MARA的MAKTX在数据库里保存的和屏幕显示的不一致含有空格差异那你分组出来就会把“相同的物料名”拆成多组。这种字符集上的坑常规调试根本看不出来。我遇到过一个案例GROUP BY ltrim(maktx)因为maktx有空格但Open SQL的LTRIM支持又有限后来干脆在ABAP里做用CONDENSE字符串再哈希。提一个关键点GROUP BY中的字段顺序影响结果集的内表字段顺序不内表字段顺序由INTO结构决定。通常我们用INTO CORRESPONDING FIELDS OF TABLE那么内表字段顺序和结构定义一致。如果结构定义里字段顺序和SELECT列表不一致那结果会按对应关系放入跟GROUP BY无关。但如果你用INTO TABLE gt_itab而没有对应的结构那么内表是扁平结构按SELECT顺序填充。这里有个老ABAP的常见错误SELECT matnr SUM(menge) GROUP BY matnr INTO TABLE lt_data。lt_data结构是(matnr, summenge)结果SUM(menge)会真正存到对应字段里。但一旦字段名冲突比如结构里第二个字段也叫menge那SUM(menge)会存到menge字段ABAP不会报错逻辑上你还能用只是语义不清晰。建议建专用结构别偷懒。还有GROUP BY和DISTINCT的关系。DISTINCT是去重GROUP BY是聚合加去重。如果你只要去重可以用DISTINCT但如果你想同时SUM或COUNT必须GROUP BY。有些人在SELECT里写DISTINCT SUM(menge)这很怪SUM的结果是一个单一值DISTINCT没有意义。而且ABAP也不允许这样写。实际上DISTINCT和GROUP BY在同一SQL中互斥。DISTINCT的实现底层往往也是分组算子所以性能上两者相差不大。选择取决于语义。还有COUNT的坑。SELECT matnr, COUNT() FROM vbap GROUP BY matnr在ABAP里你要把数据集放在内表通常用COUNT() AS cnt。如果表有重复行COUNT(*)统计所有行数。如果你希望统计“非空某字段”的行数要写COUNT(werks)。COUNT(werks)会忽略NULL。但ABAP数据库表中字段通常NOT NULL所以差别不大。但表允许空值时注意区分。还有COUNT(DISTINCT werks)这种在ABAP Open SQL里不支持老版本的语法不认识。如果你要统计组内不同工厂数量只能查询后ABAP去重或者用AMDP。这是Open SQL的一个短板。再说一个性能上的常见误区GROUP BY三个字段看起来比GROUP BY两个字段“更重”其实不一定。结果集行数是关键。如果你两个字段的组合基数比三个字段大那两个字段的GROUP BY也许更慢。因为聚合算法的复杂度和输出行数、解析的输入行数相关。所以写GROUP BY前最好心里先估一下组数。另外GROUP BY多个字段时索引的匹配度也很关键。HANA上列存表对GROUP BY的预处理非常激进但它的优化器依赖于统计信息。如果你刚加载大量数据没有更新统计执行计划可能跑偏。这个问题在HANA上尤其突出。我遇到过GROUP BY执行从秒级变成几分钟后来用HANA Studio的“执行计划分析”一看发现没走列存的基于列的聚合而是做了翻硬盘的大扫描。刷新统计信息后恢复。所以在ABAP里写好GROUP BY只是第一步数据库端的统计信息维护同样重要。现在说说ORDER BY的索引优化。如果你ORDER BY的字段顺序恰好是索引的前缀顺序数据库可以读取索引并直接得到有序结果避免显式排序。但如果ORDER BY的方向不一致比如索引是升序你要求降序优化器可能反向扫描索引这也快。如果多列排序方向不一致比如一列升序一列降序索引只能提供单一方向需要显式排序。HANA有些版本支持索引降序但OPEN SQL不一定能告知数据库方向。所以如果数据量大担心ORDER BY的性能你可以考虑在ABAP层面SORT。但ABAP SORT也是内存排序大数据量下可能慢而且还得先把全量数据拉回来。归根到底还是要看数据量级。讲一个ORDER BY的冷门坑空值排序位置。数据库里NULL在升序时排在最前面降序时排在最后面但不同数据库不一样。ABAP内表SORT时初始值相当于NULL总是排在最前升序或最后降序实际上ABAP SORT会把初始值放在最前面升序。所以如果你在数据库ORDER BY后取回内表数据库把NULL放最后降序你再SORT一次NULL跑到前面顺序就变了。这个逻辑我在做导出Excel时遇到过明明数据库查询的排序符合业务要求代码里多了一次内表SORT好家伙空行全跑到顶部。后来我规定凡是查询内表前明确需求是“空值置底”还是“空值置顶”然后统一用数据库的ORDER BY加NULLS LAST如果支持或者ABAP的SORT加STABLE配合前后分开处理。但ABAP Open SQL不支持NULLS LAST除非用AMDP。所以更常见做法是在ABAP层面用两段排序先排序非空的再把空的行放到末尾。这让我觉得Open SQL的排序能力真是有限。另外GROUP BY和ORDER BY一起使用时在ABAP中ORDER BY可以引用聚合函数吗?比如ORDER BY SUM(menge) DESCENDING。这个我之前提过可以但要注意书写位置。如果你的SELECT列表是matnr SUM(menge)而ORDER BY是SUM(menge)ABAP会重复计算聚合。语法没问题但效率略低。更优雅的做法是给SUM取别名并ORDER BY别名但前面说过别名坑。折中方案SELECT matnr AS matnr, SUM(menge) AS total然后ORDER BY total。在比较新的ABAP版本7.40中这个语法是可以的。我确认过在S/4HANA的Open SQL中别名在ORDER BY里可用。但在老ECC版本不行。为了兼容我写博客时一般建议先不用别名直接原表达式。如果你用的是BTP/Steampunk就直接用别名没问题。技术文章要注明环境。写到这里我想起了一个所有ABAP程序员都绕不开的老话题SELECT * 和GROUP BY。如果你写SELECT * FROM vbap GROUP BY matnr这基本必挂。因为SELECT *会展开所有字段而所有字段不可能都在GROUP BY里。ABAP的语法检查会报错“某个字段必须在GROUP BY中出现”。如果你遇到了一个程序没报错那可能是旧系统里SELECT *被自动展开后ABAP只取了前几个字段后几个字段全没匹配。这种程序千万别碰改起来会让人崩溃。有一个真实案例某接口程序在测试环境一直正常生产却报“列无效”。检查发现生产系统的表结构比测试多了一个字段而SELECT *在GROUP BY语句中把新字段也带进去了导致分组逻辑错误。幸亏语法检查在ABAP端没拦数据库报错不然就会产生错误数据。这就是为什么我要求团队写SQL必须列出字段列表禁止SELECT *。还有一个从性能角度出发的建议GROUP BY之后的ORDER BY尽量和GROUP BY用相同的字段顺序。比如GROUP BY matnr, erdat你就ORDER BY matnr, erdat。这样数据库可以在分组过程中就保持顺序省去一次显式的排序操作。如果你ORDER BY erdat, matnr就可能需要额外排序。这个规则不绝对但大多数情况下有效。写代码的时候稍微调整一下字段顺序就能带来收益何乐而不为。再补充一个点FOR ALL ENTRIES结果集为空时整个SELECT会被跳过。这意味着你的内表lt_range是空的后面的GROUP BY也不执行。这个行为设计是为了避免生成无条件全表查询。但如果你的业务逻辑在没有条件时希望返回全表汇总就不能依赖FOR ALL ENTRIES。我见过有人给lt_range填了一个初始值以为能绕过结果查出来不对。正确做法是单独用IF条件判断没有范围时走另一条不带FOR ALL ENTRIES的SQL。这和GROUP BY无关但遇到的人很多。说到GROUP BY不能不提ABAP 7.40之后的新内表构造和GROUP BY在ABAP语言层面的增强比如GROUP BY in FOR loop即内表循环分组算子。这是ABAP的表达式不是SQL的GROUP BY。比如lt_grp VALUE #( lt_data GROUP BY ( field matnr ) LET total SUM( menge ) …)这种新语法确实方便可以在应用层做分组而且不用担心数据库方言。但它仍然会先把全量数据载入内表性能上限在那里。对于小表无所谓大表不要用。而且这个内表分组算子有个很隐蔽的问题它只保留每组的第一条记录作为组头你如果想取组内某些字段的值仍然可能不确定。所以我在项目中还是以SQL的GROUP BY为主内表分组只用于配置表或小数据量。最后回到文章开头那个半夜电话。后来我帮他改成了GROUP BY并且特意加上ORDER BY matnr发现结果还是不稳。调了半天才意识到他用的是一个内联声明SELECT matnr, SUM(menge) AS total FROM vbap GROUP BY matnr ORDER BY total INTO DATA(lt_sum)。在7.40语法下这看起来挺漂亮。问题跑了一段时间后某些行total值相同ORDER BY total就没有绝对顺序数据库返回顺序变了用户看到明细行位置变来变去以为数据出错了。解决方案ORDER BY matnr, total。也就是增加一个唯一性字段作为次级排序。这个经验非常实用任何ORDER BY都尽量带上具有唯一性的字段如物料号、文档号保证总序稳定。如果你ORDER BY里只有金额同金额的行乱序是正常的用户会认为是bug。加一个主键字段做次级排序天下太平。经验性的建议写几条实用的。第一写GROUP BY之前先问自己聚合粒度是什么把所有非聚合字段都列出来一字不差。第二ORDER BY永远配合GROUP BY的字段顺序来写除非你有专门理由。第三能用数据库聚合就不要手工循环但要注意数据库方言限制。第四NULL和初始值的问题一旦遇到先想想排序规则和分组规则是否符合ABAP习惯。第五做报表时最终展示的排序不要依赖数据库用ABAP SORT再排一次并添加STABLE选项同时保证排序键包含唯一标识。这不是SQL不好而是应用需要稳定可预测的顺序。写到最后有点感慨。ABAP这门语言虽然老但Open SQL的细节依然值得钻研。GROUP BY和ORDER BY看起来就两个单词背后是数据库引擎的执行原理再加上ABAP特有的语法限制不小心就会掉进坑里。希望这篇文章能给你一些启发至少半夜电话能少一点。
返回列表