RPGLE外部过程返回多维数据结构时首行重复问题求助
问题
定义了一个返回dim(256)的OrderDs外部过程,调试时过程内数据正确,但主程序调用后,仅第一行数据被重复打印256次。执行OrderDs= getOrderDetails(iCusNo:iFrmDate:iToDate);后,OrderDs中所有元素均为第一行数据,循环处理也无效,请教如何正确获取外部过程返回的多维数据结构?
外部过程代码
**Free dcl-proc getOrderDetails export; dcl-ds OrderDs dim(256) Qualified; ORDNO zoned(5) inz; ORDDATE zoned(8) inz; LINNO zoned(3) inz; ITMNO zoned(5) inz; ITMQTY zoned(5) inz; end-ds; dcl-pi *n likeds(OrderDs) dim(256); iCusNo zoned(5); iFrmDate zoned(8); iToDate zoned(8); end-pi; dcl-s sqlQuery2 varchar(1000); dcl-s v_RowsFetched Int(5) inz(0); sqlQuery2 = ' Select ORDS101A.ORDNO, ' + ' ORDS101A.ORDDATE, ' + ' ORDS102A.LINNO, ' + ' ORDS102A.ITMNO, ' + 'ORDS102A.ITMQTY ' + 'AS ITMQTY FROM ' + 'ORDS101A JOIN ORDS102A ' + ' ON ORDS101A.ORDNO = ORDS102A.ORDNO ' + 'WHERE ORDS101A.ORDDATE '+ 'BETWEEN ? and ?' + ' and (ORDS101A.CUSNO = ?) ' + 'order by ORDS101A.ORDNO,ORDS102A.LINNO'; exec sql Prepare stmt2 from :sqlQuery2; exec sql declare OrdCursor scroll cursor for stmt2; exec sql open OrdCursor using :iFrmDate, :iToDate, :iCusNo; Exec Sql fetch next from OrdCUrsor for 5 rows into :OrderDs; v_RowsFetched = sqlerrd(3); exec sql close OrdCursor ; return OrderDs ; end-proc;
主程序代码
HDFTACTGRP(*NO) BNDDIR('MYBNDDIR1') FQSYSPRT O F 132 PRINTER **Free dcl-f ord101fm workstn; //**********************Variables Declaration********************// dcl-s iCusNo zoned(5); dcl-s iFrmDate zoned(8); dcl-s iToDate zoned(8); dcl-s pCusNam char(30) inz; dcl-s pOrdNo zoned(5) inz; dcl-s pOrdDate zoned(8) inz; dcl-s pLinno zoned(3) inz; dcl-s pItmno zoned(5) inz; dcl-s pItmQty zoned(5) inz; dcl-s Index zoned(5) inz(1); dcl-s Sqlrows Int(5) inz(100); //*******************Procedures Declaration******************* *// dcl-ds OrderDs dim(256) Qualified; ORDNO zoned(5) inz; ORDDATE zoned(8) inz; LINNO zoned(3) inz; ITMNO zoned(5) inz; ITMQTY zoned(5) inz; end-ds; dcl-pr getOrderDetails likeDs(OrderDs) extproc('GETORDERDETAILS'); iCusNo zoned(5); iFrmDate zoned(8); iToDate zoned(8); end-pr; iCusNo= 1234; iFrmDate=20010912; iToDate=20030912; Clear OrderDs; OrderDs= getOrderDetails(iCusNo:iFrmDate:iToDate); EXCEPT HEADER; for index=1 to %elem(OrderDs); if OrderDs(Index).Ordno <> 0; index +=1; pCusNam = CustomerDs.oCusNam; pOrdNO = OrderDs(Index).ORDNO; pOrdDate = OrderDs(Index).ORDDATE; pLinno = OrderDs(Index).LINNO; pItmno = OrderDs(Index).ITMNO; pItmQty = OrderDs(Index).ITMQTY; EXCEPT Detail; endif; endfor; *Inlr=*On; //Printer File// OQSYSPRT E HEADER O O 30 'ORDER DETAILS REPORT' O E HEADER 1 O 20 'Customer Name' O 35 'Order No' O 45 'Order Date' O 50 'Order Line' O 60 'Item Num' O 70 'Item Quantity' O 100 'Customer Number' O 120 'Price' O 130 'Total' O E Detail 1 O pCusNam 30 O pOrdNo 35 O pOrdDate 45 O pLinno 50 O pItmno 60 O pItmQty 70 O iCusNo 100
问题分析与修复方案
1. 主程序循环逻辑错误(核心问题)
主程序for循环内的index +=1是导致数据重复/跳过的关键:
- 初始
index=1,进入if判断后先执行index +=1变为2,随后读取OrderDs(2)的数据 - 下一次循环
index自动递增到3,再次进入if又变为4,以此类推,直接跳过所有奇数索引的元素 - 未被正确填充的数组后续元素会保留初始值或重复第一行数据,最终出现重复打印的现象
修复:删除if块内的index +=1,让for循环自动控制索引递增
2. 过程返回数据的优化
原过程仅fetch最多5行数据,且未返回实际获取的行数,建议:
- 添加输出参数返回实际获取的总行数,避免主程序遍历整个256元素的空数组
- 循环
fetch直到无数据,确保所有符合条件的行都被填充到数组中
3. 其他细节修正
- 主程序中
CustomerDs未定义,需确保该数据结构已正确声明或替换为实际可用变量 - 移除主程序中无效的注释代码
修改后的主程序循环部分
EXCEPT HEADER; for index=1 to %elem(OrderDs); if OrderDs(Index).Ordno <> 0; pCusNam = CustomerDs.oCusNam; // 确保CustomerDs已正确定义 pOrdNO = OrderDs(Index).ORDNO; pOrdDate = OrderDs(Index).ORDDATE; pLinno = OrderDs(Index).LINNO; pItmno = OrderDs(Index).ITMNO; pItmQty = OrderDs(Index).ITMQTY; EXCEPT Detail; endif; endfor;
带返回行数的外部过程修改
**Free dcl-proc getOrderDetails export; dcl-ds OrderDs dim(256) Qualified; ORDNO zoned(5) inz; ORDDATE zoned(8) inz; LINNO zoned(3) inz; ITMNO zoned(5) inz; ITMQTY zoned(5) inz; end-ds; dcl-pi *n likeds(OrderDs) dim(256); iCusNo zoned(5); iFrmDate zoned(8); iToDate zoned(8); oRowsFetched Int(5) options(*nopass:*output); // 添加输出参数返回实际行数 end-pi; dcl-s sqlQuery2 varchar(1000); dcl-s v_RowsFetched Int(5) inz(0); dcl-s v_TotalRows Int(5) inz(0); sqlQuery2 = ' Select ORDS101A.ORDNO, ' + ' ORDS101A.ORDDATE, ' + ' ORDS102A.LINNO, ' + ' ORDS102A.ITMNO, ' + 'ORDS102A.ITMQTY ' + 'AS ITMQTY FROM ' + 'ORDS101A JOIN ORDS102A ' + ' ON ORDS101A.ORDNO = ORDS102A.ORDNO ' + 'WHERE ORDS101A.ORDDATE '+ 'BETWEEN ? and ?' + ' and (ORDS101A.CUSNO = ?) ' + 'order by ORDS101A.ORDNO,ORDS102A.LINNO'; exec sql Prepare stmt2 from :sqlQuery2; exec sql declare OrdCursor scroll cursor for stmt2; exec sql open OrdCursor using :iFrmDate, :iToDate, :iCusNo; // 循环fetch直到无数据,填充整个数组 dow sqlcode = 0; Exec Sql fetch next from OrdCUrsor for 256 rows into :OrderDs; v_RowsFetched = sqlerrd(3); v_TotalRows += v_RowsFetched; if v_RowsFetched < 256; leave; endif; enddo; exec sql close OrdCursor ; // 返回实际获取的行数 if %parms() >=4; oRowsFetched = v_TotalRows; endif; return OrderDs ; end-proc;
优化后的主程序调用部分
// 更新过程声明,添加输出参数 dcl-pr getOrderDetails likeDs(OrderDs) extproc('GETORDERDETAILS'); iCusNo zoned(5); iFrmDate zoned(8); iToDate zoned(8); oRowsFetched Int(5) options(*output); end-pr; dcl-s v_ActualRows Int(5) inz(0); iCusNo= 1234; iFrmDate=20010912; iToDate=20030912; Clear OrderDs; OrderDs= getOrderDetails(iCusNo:iFrmDate:iToDate:v_ActualRows); EXCEPT HEADER; // 根据实际获取的行数循环,避免遍历空元素 for index=1 to v_ActualRows; pCusNam = CustomerDs.oCusNam; pOrdNO = OrderDs(Index).ORDNO; pOrdDate = OrderDs(Index).ORDDATE; pLinno = OrderDs(Index).LINNO; pItmno = OrderDs(Index).ITMNO; pItmQty = OrderDs(Index).ITMQTY; EXCEPT Detail; endfor;
内容的提问来源于stack exchange,提问作者Rituraj singh
相关产品推荐
相关产品推荐

