无UNION触发Oracle ORA-01790?诡异workaround成因解析
错误本质
ORA-01790的核心要求是:在全外连接(FULL OUTER JOIN)、集合操作(如UNION)等场景中,对应位置的表达式必须具有完全一致的数据类型(包括精度、刻度等细节)。单独执行view1时正常,是因为Oracle执行视图时的计划逻辑,与view2查询view1时的合并计划逻辑存在差异。
触发场景的深层原因
Oracle视图的执行采用查询计划合并机制:当view2执行select * from view1时,Oracle不会先单独执行view1得到结果,而是将view1的SQL与view2的查询合并为一个整体执行计划。此时,原view1中的全外连接分支(cc、iac、pc子查询)会被直接纳入整体计划,Oracle会对全外连接两边的对应列进行严格的类型校验。
问题出在cc.CENTRAL_COST与另外两个cost列(iac.indirect_attri_cost、pc.premises_cost)的数据类型细节不一致——比如前者是NUMBER(12,3),后者是NUMBER(10,2)。单独执行view1时,Oracle在计算total_cost时会自动做隐式类型转换,不会触发校验;但合并计划后,全外连接的类型校验逻辑优先级更高,认为对应表达式类型不匹配,抛出ORA-01790。
临时解决方案的原理
将cc.CENTRAL_COST先通过TO_CHAR转成字符串,再用TO_NUMBER转回数字,本质是强制重置数据类型的精度与刻度:
TO_CHAR会剥离原数字的精度、刻度属性,转成纯字符串形式;TO_NUMBER转换后,会生成Oracle默认的无精度/刻度限制的NUMBER类型,与另外两个cost列的类型细节完全对齐,从而通过全外连接的类型校验。
优化目标绕过错误的原因
修改view1的优化目标(如从ALL_ROWS改为FIRST_ROWS)会改变Oracle的执行计划生成逻辑:
- 优化目标变更后,Oracle可能选择先独立执行各子查询(cc、iac、pc),再进行连接的执行路径,而非合并整体计划;
- 子查询执行后,结果列的类型已经统一(隐式转换完成),后续连接与计算时不再触发严格的全外连接类型校验,因此绕过了错误。
内容的提问来源于stack exchange,提问作者losiu

