Join关联查询中动态排序实现方式正确性及优化咨询
需求背景
需要关联pt_mstr、in_mstr两张表开发报表界面,已完成部分代码编写,核心需求为支持输出结果动态排序:
- 定义变量
lvc_sort作为排序参数 - 参数值为1时,按产品线(prod line)排序
- 参数值为2时,按状态(status)排序
现有核心实现代码如下:
IF lvc_sort = 1 THEN DO: FOR EACH pt_mstr no-lock WHERE pt_domain = global_domain AND pt_part >= lvc_part AND pt_part <= lvc_part1 AND pt_part_type >= lvc_part_type AND pt_part_type <= lvc_part_type1 AND pt_prod_line >= lvc_prod_line AND pt_prod_line <= lvc_prod_line1 AND pt_status >= lvc_status AND pt_status <= lvc_status1, EACH in_mstr WHERE in_domain = pt_domain AND in_part = pt_part BREAK BY pt_prod_line: FIND FIRST tt NO-LOCK WHERE tt_part = pt_part AND tt_site = in_site NO-ERROR.
现有实现问题判断
当前实现不完整,无法满足需求,存在明确缺陷:
- 仅编写了
lvc_sort=1的查询分支,完全缺失lvc_sort=2(按状态排序)的处理逻辑,参数传2时不会执行任何数据查询操作。 - 如果直接复制现有循环补全
lvc_sort=2分支,会产生大量重复代码,后续修改筛选条件时需要同步修改两处,极易出现漏改导致的逻辑不一致问题。 - 当前
in_mstr关联逻辑未加站点等范围筛选,若物料存在多站点库存数据,会拉取全量站点记录,数据量大时会有明显性能问题。
更合理的实现方案
不需要编写两套重复的查询逻辑,生产环境常用两种实现路径,可根据场景选择:
方案1:临时表预加载+索引排序(推荐,稳定性最高)
核心逻辑是先一次性将所有符合筛选条件的数据查询写入临时表,为临时表创建对应排序规则的索引,最后根据传入参数选择对应索引遍历输出。这种写法全为静态代码,调试方便,不会出现动态SQL索引失效问题,大数据量下性能最优。
示例代码:
/* 定义报表临时表,提前建对应排序规则的索引 */ DEFINE TEMP-TABLE tt_report FIELD pt_part LIKE pt_mstr.pt_part FIELD pt_prod_line LIKE pt_mstr.pt_prod_line FIELD pt_status LIKE pt_mstr.pt_status FIELD in_site LIKE in_mstr.in_site /* 此处补充报表需要的其他字段 */ INDEX idx_sort_prodline IS PRIMARY pt_prod_line pt_part in_site INDEX idx_sort_status pt_status pt_part in_site. /* 单次查询拉取全量符合条件的数据,写入临时表 */ FOR EACH pt_mstr NO-LOCK WHERE pt_domain = global_domain AND pt_part >= lvc_part AND pt_part <= lvc_part1 AND pt_part_type >= lvc_part_type AND pt_part_type <= lvc_part_type1 AND pt_prod_line >= lvc_prod_line AND pt_prod_line <= lvc_prod_line1 AND pt_status >= lvc_status AND pt_status <= lvc_status1, EACH in_mstr NO-LOCK WHERE in_domain = pt_domain AND in_part = pt_part: /* 此处可补充in_site等字段的筛选逻辑,缩小查询范围 */ CREATE tt_report. ASSIGN tt_report.pt_part = pt_part tt_report.pt_prod_line = pt_prod_line tt_report.pt_status = pt_status tt_report.in_site = in_site. /* 此处给其他报表字段赋值 */ END. /* 根据参数选择对应索引遍历输出 */ CASE lvc_sort: WHEN 1 THEN FOR EACH tt_report USE-INDEX idx_sort_prodline: /* 此处写报表输出、tt表匹配逻辑 */ FIND FIRST tt NO-LOCK WHERE tt_part = tt_report.pt_part AND tt_site = tt_report.in_site NO-ERROR. END. WHEN 2 THEN FOR EACH tt_report USE-INDEX idx_sort_status: /* 此处写报表输出、tt表匹配逻辑 */ FIND FIRST tt NO-LOCK WHERE tt_part = tt_report.pt_part AND tt_site = tt_report.in_site NO-ERROR. END. END CASE.
方案2:动态查询实现(代码最简洁)
利用Progress ABL的动态查询句柄,根据参数动态拼接排序字段,仅需编写一次查询逻辑,代码冗余度最低,适合报表逻辑简单、字段少的轻量场景。
示例代码:
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO. DEFINE VARIABLE cSortField AS CHARACTER NO-UNDO. /* 根据参数确定排序字段,加默认兜底逻辑避免参数异常 */ CASE lvc_sort: WHEN 1 THEN cSortField = "pt_mstr.pt_prod_line". WHEN 2 THEN cSortField = "pt_mstr.pt_status". OTHERWISE cSortField = "pt_mstr.pt_part". END CASE. /* 创建动态查询 */ CREATE QUERY hQuery. hQuery:SET-BUFFERS(BUFFER pt_mstr:HANDLE, BUFFER in_mstr:HANDLE). hQuery:QUERY-PREPARE(SUBSTITUTE( "FOR EACH pt_mstr NO-LOCK WHERE pt_domain = &1 " + "AND pt_part >= &2 AND pt_part <= &3 " + "AND pt_part_type >= &4 AND pt_part_type <= &5 " + "AND pt_prod_line >= &6 AND pt_prod_line <= &7 " + "AND pt_status >= &8 AND pt_status <= &9, " + "EACH in_mstr NO-LOCK WHERE in_domain = pt_mstr.pt_domain " + "AND in_part = pt_mstr.pt_part " + "BREAK BY &10", QUOTER(global_domain), QUOTER(lvc_part), QUOTER(lvc_part1), QUOTER(lvc_part_type), QUOTER(lvc_part_type1), QUOTER(lvc_prod_line), QUOTER(lvc_prod_line1), QUOTER(lvc_status), QUOTER(lvc_status1), cSortField )). hQuery:QUERY-OPEN(). /* 遍历查询结果 */ DO WHILE hQuery:GET-NEXT(): FIND FIRST tt NO-LOCK WHERE tt_part = pt_part AND tt_site = in_site NO-ERROR. /* 此处写报表输出逻辑 */ END. /* 释放资源 */ hQuery:QUERY-CLOSE(). DELETE OBJECT hQuery.
内容的提问来源于stack exchange,提问作者user19007432
相关产品推荐
相关产品推荐

