Oracle18c列子查询取SDO_GEOMETRY第二坐标返回空原因咨询
原因说明
这是Oracle ROWNUM伪列的固有运行逻辑导致的,和SDO_GEOMETRY本身的坐标存储逻辑无关:
ROWNUM是Oracle逐行从结果集取数据时临时分配的序号,永远给当前取出的第一行分配1,只有第一行被保留、成功返回之后,才会给下一行分配2,后续序号以此类推。- 当你在子查询里写
WHERE ROWNUM = 2时,执行逻辑是这样的:- 取出坐标数组的第一个值,给它分配
ROWNUM=1 - 判断
ROWNUM=2条件不成立,这行被丢弃 - 继续取数组里的下一个值,这时候它成了当前结果集的第一行,还是被分配
ROWNUM=1 - 条件依旧不成立,继续丢弃,循环到数组结束也没有符合条件的行,最终子查询返回空,外层拿到的就是null。
- 取出坐标数组的第一个值,给它分配
- 而
ROWNUM=1能正常运行,是因为取出第一个值时分配的行号刚好满足条件,直接返回即可,不会出现行号永远到不了2的问题。
你备注里提到的
FETCH FIRST ROW ONLY行为不符合预期,也是同一个原因:没有额外嵌套子查询固定行号的话,优化器会直接把取数逻辑下推,不会按你预想的先展开全量坐标再偏移取数。
正确写法
要拿到固定位置的坐标值,需要先嵌套一层子查询,给展开后的所有坐标按顺序分配好连续行号,再按行号筛选,示例如下:
with cte as ( select sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array( 1, 2, 3, 4 )) shape from dual union all select sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array( 5, 6, 7, 8, 9,10 )) shape from dual union all select sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(11,12, 13,14, 15,16, 17,18)) shape from dual) select (select ord from ( select column_value ord, rownum rn from table((shape).sdo_ordinates) ) where rn = 2 ) startpoint_y from cte
执行后会返回你预期的结果:
STARTPOINT_Y ------------ 2 6 12
补充说明:直接查询table((shape).sdo_ordinates)时,返回值的顺序和你写入SDO_ORDINATE_ARRAY时的顺序完全一致,不需要额外加排序字段,只要正确分配行号就能拿到对应位置的坐标。你提到的cross join table(sdo_util.getvertices(shape))的方案,本质也是先把全量顶点展开为行集再做筛选,和上面修正后的逻辑是一致的。
内容的提问来源于stack exchange,提问作者User1974
相关产品推荐
相关产品推荐

