PL/SQL存储过程用WITH子句出现ORA-00904无效标识符错误
PL/SQL存储过程中WITH子句报错ORA-00904的解决
问题现象
在PL/SQL存储过程中使用WITH子句获取数据时,出现以下错误:
Error(550,37): PL/SQL: ORA-00904: "Q2_DATA"."AR_LENGTH": invalid identifier
原始查询语句
WITH q1_data (SPAN_ID, MAINT_ZONE_CODE, NE_LENGTH, UG_LENGTH, AR_LENGTH) AS ( SELECT rj_span_id AS SPAN_ID, rj_maintenance_zone_code AS maint_zone_code, Round(SUM(Nvl(calculated_length, 0) / 1000), 4) AS NE_LENGTH, Round(SUM( CASE WHEN rj_construction_methodology NOT LIKE '%AERIAL%' AND rj_construction_methodology NOT LIKE '%CLAMP%' OR rj_construction_methodology IS NULL THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS UG_LENGTH, Round(SUM( CASE WHEN rj_construction_methodology LIKE '%AERIAL%' OR rj_construction_methodology LIKE '%CLAMP%' THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS AR_LENGTH FROM ne.mv_span@ne WHERE Trim(rj_span_id) = PSPAN_ID AND inventory_status_code = 'IPL' AND NOT Regexp_like (Nvl(rj_intracity_link_id, '-'), '_9', 'i') AND rj_maintenance_zone_code = PMAINTZONECODE GROUP BY rj_span_id, rj_maintenance_zone_code ), q2_data (SPAN_ID, MAINT_ZONE_CODE, NE_LENGTH, UG_LENGTH, AR_LENGTH) AS ( SELECT span_id as SPAN_ID, maintenancezonecode AS MAINT_ZONE_CODE, maint_zone_ne_span_length AS NE_LENGTH, fsa_ug AS UG_LENGTH, fsa_aerial AS AR_LENGTH FROM tbl_fiber_inv_jobs WHERE span_id = PSPAN_ID ) SELECT q1.SPAN_ID, q1.MAINT_ZONE_CODE, q1_data.NE_LENGTH - Nvl(q2_data.NE_LENGTH, 0) as NE_LENGTH, q1_data.UG_LENGTH - Nvl(q2_data.UG_LENGTH, 0) as UG_LENGTH, q1_data.AR_LENGTH - Nvl(q2_data.AR_LENGTH, 0) as AR_LENGTH FROM q1_data q1 LEFT JOIN q2_data q2 ON(q2.SPAN_ID = q1.SPAN_ID) ORDER BY q1.SPAN_ID, q1.MAINT_ZONE_CODE;
更新:完整存储过程
PROCEDURE Get_spaninfo_by_span_mz_new (pspan_id IN NVARCHAR2, pmaintzonecode IN VARCHAR2, pspantype IN NVARCHAR2, pspaninfodata OUT SYS_REFCURSOR) AS VAR_PARTIAL_QTY NUMBER; BEGIN VAR_PARTIAL_QTY :=0; SELECT COUNT(JOB_ID) INTO VAR_PARTIAL_QTY from tbl_fiber_inv_jobs where span_id = PSPAN_ID AND JOB_FLAG = 1; IF pspantype = 'INTERCITY' AND VAR_PARTIAL_QTY = 0 AND Length(pspan_id) = 21 THEN BEGIN OPEN pspaninfodata FOR SELECT rj_span_id AS span_id, rj_maintenance_zone_code AS maint_zone_code, Round(SUM(Nvl(calculated_length, 0) / 1000), 4) AS ne_length, Round(SUM(CASE WHEN rj_construction_methodology NOT LIKE '%AERIAL%' AND rj_construction_methodology NOT LIKE '%CLAMP%' OR rj_construction_methodology IS NULL THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS ug_length, Round(SUM(CASE WHEN rj_construction_methodology LIKE '%AERIAL%' OR rj_construction_methodology LIKE '%CLAMP%' THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS ar_length FROM ne.mv_span@ne -- FROM APP_FTTX.span@sat WHERE Trim(rj_span_id) = pspan_id AND inventory_status_code = 'IPL' AND NOT Regexp_like (Nvl(rj_intracity_link_id, '-'), '_9', 'i') AND rj_maintenance_zone_code = pmaintzonecode GROUP BY rj_span_id, rj_maintenance_zone_code; END; ELSE WITH q1_data (SPAN_ID, MAINT_ZONE_CODE, NE_LENGTH, UG_LENGTH, AR_LENGTH) AS ( SELECT rj_span_id AS SPAN_ID, rj_maintenance_zone_code AS maint_zone_code, Round(SUM(Nvl(calculated_length, 0) / 1000), 4) AS NE_LENGTH, Round(SUM( CASE WHEN rj_construction_methodology NOT LIKE '%AERIAL%' AND rj_construction_methodology NOT LIKE '%CLAMP%' OR rj_construction_methodology IS NULL THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS UG_LENGTH, Round(SUM( CASE WHEN rj_construction_methodology LIKE '%AERIAL%' OR rj_construction_methodology LIKE '%CLAMP%' THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS AR_LENGTH FROM ne.mv_span@ne WHERE Trim(rj_span_id) = PSPAN_ID AND inventory_status_code = 'IPL' AND NOT Regexp_like (Nvl(rj_intracity_link_id, '-'), '_9', 'i') AND rj_maintenance_zone_code = PMAINTZONECODE GROUP BY rj_span_id, rj_maintenance_zone_code ), q2_data (SPAN_ID, MAINT_ZONE_CODE, NE_LENGTH, UG_LENGTH, AR_LENGTH) AS ( SELECT span_id as SPAN_ID, maintenancezonecode AS MAINT_ZONE_CODE, maint_zone_ne_span_length AS NE_LENGTH, fsa_ug AS UG_LENGTH, fsa_aerial AS AR_LENGTH FROM tbl_fiber_inv_jobs WHERE span_id = PSPAN_ID ) SELECT q1.SPAN_ID, q1.MAINT_ZONE_CODE, q1.NE_LENGTH - Nvl(q2.NE_LENGTH, 0) as NE_LENGTH, q1.UG_LENGTH - Nvl(q2.UG_LENGTH, 0) as UG_LENGTH, q1.AR_LENGTH - Nvl(q2.AR_LENGTH, 0) as AR_LENGTH FROM q1_data q1 LEFT JOIN q2_data q2 ON(q2.SPAN_ID = q1.SPAN_ID) ORDER BY q1.SPAN_ID, q1.MAINT_ZONE_CODE; END IF; END get_spaninfo_by_span_mz_new;
更新2:修改后的存储过程版本
PROCEDURE Get_spaninfo_by_span_mz_new ( pspan_id IN NVARCHAR2, pmaintzonecode IN VARCHAR2, pspantype IN NVARCHAR2, pspaninfodata OUT SYS_REFCURSOR ) AS VAR_PARTIAL_QTY NUMBER; BEGIN VAR_PARTIAL_QTY :=0; SELECT COUNT(JOB_ID) INTO VAR_PARTIAL_QTY from tbl_fiber_inv_jobs where span_id = PSPAN_ID AND JOB_FLAG = 1; WITH q1_data (SPAN_ID, MAINT_ZONE_CODE, NE_LENGTH, UG_LENGTH, AR_LENGTH) AS ( SELECT rj_span_id AS SPAN_ID, rj_maintenance_zone_code AS maint_zone_code, Round(SUM(Nvl(calculated_length, 0) / 1000), 4) AS NE_LENGTH, Round(SUM( CASE WHEN rj_construction_methodology NOT LIKE '%AERIAL%' AND rj_construction_methodology NOT LIKE '%CLAMP%' OR rj_construction_methodology IS NULL THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS UG_LENGTH, Round(SUM( CASE WHEN rj_construction_methodology LIKE '%AERIAL%' OR rj_construction_methodology LIKE '%CLAMP%' THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS AR_LENGTH FROM ne.mv_span@ne WHERE Trim(rj_span_id) = PSPAN_ID AND inventory_status_code = 'IPL' AND NOT Regexp_like (Nvl(rj_intracity_link_id, '-'), '_9', 'i') AND rj_maintenance_zone_code = PMAINTZONECODE GROUP BY rj_span_id, rj_maintenance_zone_code ), q2_data (SPAN_ID, MAINT_ZONE_CODE, NE_LENGTH, UG_LENGTH, AR_LENGTH) AS ( SELECT span_id as SPAN_ID, maintenancezonecode AS MAINT_ZONE_CODE, maint_zone_ne_span_length AS NE_LENGTH, fsa_ug AS UG_LENGTH, fsa_aerial AS AR_LENGTH FROM tbl_fiber_inv_jobs WHERE span_id = PSPAN_ID ); IF pspantype = 'INTERCITY' AND Length(pspan_id) = 21 AND VAR_PARTIAL_QTY = 0 THEN BEGIN OPEN pspaninfodata FOR SELECT rj_span_id AS span_id, rj_maintenance_zone_code AS maint_zone_code, Round(SUM(Nvl(calculated_length, 0) / 1000), 4) AS ne_length, Round(SUM(CASE WHEN rj_construction_methodology NOT LIKE '%AERIAL%' AND rj_construction_methodology NOT LIKE '%CLAMP%' OR rj_construction_methodology IS NULL THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS UG_LENGTH, Round(SUM(CASE WHEN rj_construction_methodology LIKE '%AERIAL%' OR rj_construction_methodology LIKE '%CLAMP%' THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS AR_LENGTH FROM ne.mv_span@ne WHERE Trim(rj_span_id) = pspan_id AND inventory_status_code = 'IPL' AND NOT Regexp_like (Nvl(rj_intracity_link_id, '-'), '_9', 'i') AND rj_maintenance_zone_code = pmaintzonecode GROUP BY rj_span_id, rj_maintenance_zone_code; END; ELSE OPEN pspaninfodata FOR SELECT q1_data.SPAN_ID, q1_data.MAINT_ZONE_CODE, q1_data.NE_LENGTH - Nvl(q2_data.NE_LENGTH, 0) as NE_LENGTH, q1_data.UG_LENGTH - Nvl(q2_data.UG_LENGTH, 0) as UG_LENGTH, q1_data.AR_LENGTH - Nvl(q2_data.AR_LENGTH, 0) as AR_LENGTH FROM q1_data q1 LEFT JOIN q2_data q2 ON(q2.SPAN_ID = q1.SPAN_ID) ORDER BY q1.SPAN_ID, q1.MAINT_ZONE_CODE; END IF; END Get_spaninfo_by_span_mz_new;
问题分析与解决
原始查询错误原因
原始查询中已给q1_data、q2_data分别取了别名q1、q2,但SELECT字段里却用原CTE名称q1_data、q2_data引用字段,不符合SQL语法,需改用别名访问:
SELECT q1.SPAN_ID, q1.MAINT_ZONE_CODE, q1.NE_LENGTH - Nvl(q2.NE_LENGTH, 0) as NE_LENGTH, q1.UG_LENGTH - Nvl(q2.UG_LENGTH, 0) as UG_LENGTH, q1.AR_LENGTH - Nvl(q2.AR_LENGTH, 0) as AR_LENGTH FROM q1_data q1 LEFT JOIN q2_data q2 ON(q2.SPAN_ID = q1.SPAN_ID) ORDER BY q1.SPAN_ID, q1.MAINT_ZONE_CODE;
更新2版本错误原因
更新2中将WITH子句单独放在IF语句外,这是错误的。PL/SQL中WITH子句属于SELECT语句的一部分,作用域仅限于紧跟的SELECT语句,无法单独定义后在后续语句中引用。
正确做法是将WITH子句放在ELSE分支的OPEN pspaninfodata FOR后,作为游标查询的一部分:
ELSE OPEN pspaninfodata FOR WITH q1_data (SPAN_ID, MAINT_ZONE_CODE, NE_LENGTH, UG_LENGTH, AR_LENGTH) AS ( SELECT rj_span_id AS SPAN_ID, rj_maintenance_zone_code AS maint_zone_code, Round(SUM(Nvl(calculated_length, 0) / 1000), 4) AS NE_LENGTH, Round(SUM( CASE WHEN rj_construction_methodology NOT LIKE '%AERIAL%' AND rj_construction_methodology NOT LIKE '%CLAMP%' OR rj_construction_methodology IS NULL THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS UG_LENGTH, Round(SUM( CASE WHEN rj_construction_methodology LIKE '%AERIAL%' OR rj_construction_methodology LIKE '%CLAMP%' THEN Nvl(calculated_length, 0) ELSE 0 END) / 1000, 4) AS AR_LENGTH FROM ne.mv_span@ne WHERE Trim(rj_span_id) = PSPAN_ID AND inventory_status_code = 'IPL' AND NOT Regexp_like (Nvl(rj_intracity_link_id, '-'), '_9', 'i') AND rj_maintenance_zone_code = PMAINTZONECODE GROUP BY rj_span_id, rj_maintenance_zone_code ), q2_data (SPAN_ID, MAINT_ZONE_CODE, NE_LENGTH, UG_LENGTH, AR_LENGTH) AS ( SELECT span_id as SPAN_ID, maintenancezonecode AS MAINT_ZONE_CODE, maint_zone_ne_span_length AS NE_LENGTH, fsa_ug AS UG_LENGTH, fsa_aerial AS AR_LENGTH FROM tbl_fiber_inv_jobs WHERE span_id = PSPAN_ID ) SELECT q1.SPAN_ID, q1.MAINT_ZONE_CODE, q1.NE_LENGTH - Nvl(q2.NE_LENGTH, 0) as NE_LENGTH, q1.UG_LENGTH - Nvl(q2.UG_LENGTH, 0) as UG_LENGTH, q1.AR_LENGTH - Nvl(q2.AR_LENGTH, 0) as AR_LENGTH FROM q1_data q1 LEFT JOIN q2_data q2 ON(q2.SPAN_ID = q1.SPAN_ID) ORDER BY q1.SPAN_ID, q1.MAINT_ZONE_CODE; END IF;
以上修改可解决ORA-00904标识符无效错误,确保WITH子句在正确作用域内使用。
内容的提问来源于stack exchange,提问作者Nadeem
相关产品推荐
相关产品推荐

