Oracle APEX经典报表多单选组取值遇ORA-01403错误求助
ORA-01403: no data found 错误修复(Oracle APEX 经典报表单选组值获取问题)
问题背景
在Oracle APEX中使用APEX_APPLICATION.G_F30(i)获取经典报表单选组值时触发ORA-01403: no data found错误:
- 处理前4行数据(1个单选组+3个文本框)时正常
- 循环到第5行(另一个单选组)时触发错误
- 为避免同一F编号单选组只能选中一个选项,给不同行单选组分配了F20、F30编号,文本框统一使用F20
错误原因
APEX的APEX_APPLICATION.G_Fxx数组仅存储被提交的表单元素值:
- 单选组只有选中的选项才会被提交到对应F数组中,未选中的行不会生成对应数组元素
- 循环时以
G_F10.COUNT为基准(G_F10是隐藏的QUESTIONID,每行都有值),但G_F30的长度可能小于G_F10的长度,直接用G_F30(i)访问不存在的索引时触发no data found错误
解决方案
方案1:统一F编号(推荐,符合APEX表单提交逻辑)
将所有单选组和文本框统一使用F20编号,通过给每行单选组设置独立的组名,实现每行单选组独立可选。
修改后的经典报表SQL
SELECT APEX_ITEM.HIDDEN(10, Q.QUESTIONID) QUESTIONID_HID, Q.QUESTION, CASE WHEN Q.ANSWER_TYPE = 'RADIO' THEN CASE (SELECT LISTAGG(A.ANSWER_CODE, ', ') WITHIN GROUP (ORDER BY A.ANSWERID, A.ANSWER_CODE) ANSWER FROM XYZ A WHERE A.QUESTIONID = Q.QUESTIONID) WHEN 'G, P' THEN apex_item.radiogroup(20, 'G', NULL, 'Government', 'name="f20_'||Q.QUESTIONID||'"')||'<br>'|| apex_item.radiogroup(20, 'P', NULL, 'Private', 'name="f20_'||Q.QUESTIONID||'"') WHEN 'L, H, M' THEN apex_item.radiogroup(20, 'L', NULL, 'Low Income', 'name="f20_'||Q.QUESTIONID||'"')||'<br>'|| apex_item.radiogroup(20, 'H', NULL, 'High Income', 'name="f20_'||Q.QUESTIONID||'"')||'<br>'|| apex_item.radiogroup(20, 'M', NULL, 'Medium Income', 'name="f20_'||Q.QUESTIONID||'"') END ELSE APEX_ITEM.TEXT(20, NULL) END INPUTCOL FROM ABC Q WHERE Q.APPID = :APP_ID;
修改后的页面进程代码
DECLARE V_QUESTIONID INTEGER; V_ANSWER VARCHAR2(20); BEGIN FOR i in 1..APEX_APPLICATION.G_F10.COUNT LOOP V_QUESTIONID := APEX_APPLICATION.G_F10(i); -- 直接获取对应行的F20值,空值则插入空字符串 V_ANSWER := NVL(APEX_APPLICATION.G_F20(i), ''); INSERT INTO CSD_DTL (CSDID, QUESTIONID, ANSWER, CUSTOMER_POINT) VALUES(:P10_SURVEYID, V_QUESTIONID, V_ANSWER, 10); END LOOP; COMMIT; -- 将COMMIT移到循环外,提升性能 END;
方案2:保留原F编号,添加索引检查
如果不想修改报表SQL,可在进程中先检查F数组的索引是否存在,避免访问不存在的元素:
DECLARE V_QUESTIONID INTEGER; V_ANSWER_OPT VARCHAR2(20); V_ANSWER VARCHAR2(20); V_ANSWER_TYPE VARCHAR2(10); BEGIN FOR i in 1..APEX_APPLICATION.G_F10.COUNT LOOP V_QUESTIONID := APEX_APPLICATION.G_F10(i); SELECT Q.ANSWER_TYPE INTO V_ANSWER_TYPE FROM ABC Q WHERE Q.QUESTIONID = V_QUESTIONID; V_ANSWER_OPT := NULL; IF V_ANSWER_TYPE = 'RADIO' THEN SELECT LISTAGG(A.ANSWER_CODE, ', ') WITHIN GROUP (ORDER BY A.ANSWERID, A.ANSWER_CODE) ANSWER INTO V_ANSWER_OPT FROM XYZ A WHERE A.QUESTIONID = V_QUESTIONID; END IF; V_ANSWER := NULL; IF V_ANSWER_OPT = 'G, P' THEN -- 检查G_F20是否存在当前索引 IF i <= APEX_APPLICATION.G_F20.COUNT THEN V_ANSWER := APEX_APPLICATION.G_F20(i); END IF; ELSIF V_ANSWER_OPT = 'L, H, M' THEN -- 检查G_F30是否存在当前索引 IF i <= APEX_APPLICATION.G_F30.COUNT THEN V_ANSWER := APEX_APPLICATION.G_F30(i); END IF; ELSE IF i <= APEX_APPLICATION.G_F20.COUNT THEN V_ANSWER := APEX_APPLICATION.G_F20(i); END IF; END IF; INSERT INTO CSD_DTL (CSDID, QUESTIONID, ANSWER, CUSTOMER_POINT) VALUES(:P10_SURVEYID, V_QUESTIONID, NVL(V_ANSWER, ''), 10); END LOOP; COMMIT; END;
内容的提问来源于stack exchange,提问作者JAWAD KHAN
相关产品推荐
相关产品推荐

