oracle 将SDO_GEOMETRY坐标用作列子查询中的表

fcg9iug3  于 2023-08-03  发布在  Oracle
关注(0)|答案(3)|浏览(134)
  • Oracle 18c:*

我正在试验在查询中使用SDO_GEOMETRY顶点的不同技术。
例如,在列子查询中将坐标作为表使用:

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 
        column_value
    from
        table((shape).sdo_ordinates) 
    where 
        rownum = 1       --Side note: "FETCH FIRST ROW ONLY" doesn't work the way I expected. It selects 1 for each startpoint X, which is incorrect. I'm not sure why it works that way.
    ) startpoint_x
from 
    cte

STARTPOINT_X
------------
           1
           5
          11

字符串
该查询按预期工作。它获取每个几何体的起点X。
同样,我想知道是否可以使用相同的技术来获得每个几何体的起点Y。我将通过将rownum = 1更改为rownum = 2来从坐标列表中获得第二个坐标:

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 
        column_value
    from
        table((shape).sdo_ordinates) 
    where 
        rownum = 2
    ) startpoint_y
from 
    cte

STARTPOINT_Y
------------
      (null)
      (null)
      (null)


但这并不像我想象的那样。它返回null,而我希望它返回:

STARTPOINT_Y
------------
           2
           6
          12

问题:

为什么这个查询对起点X rownum = 1有效,而对起点Y rownum = 2无效?
我知道还有其他方法可以与顶点交互,例如cross join table(sdo_util.getvertices(shape))。这是可行的,但我想了解纵坐标在列子查询中如何作为表。

slwdgvem

slwdgvem1#

你可以使用一个函数:

with FUNCTION get_ordinate(
  shape SDO_GEOMETRY,
  idx   PLS_INTEGER
) RETURN NUMBER
IS
BEGIN
  RETURN shape.sdo_ordinates(idx);
END;
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 get_ordinate(c.shape, 2) AS start_point_y
from   cte c

字符串
CROSS JOIN LATERAL(或CROSS APPLY):

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 sp.start_point AS start_point_y
from   cte c
       CROSS JOIN LATERAL (
         SELECT column_value AS start_point, ROWNUM AS start_point_index
         FROM   table(c.shape.sdo_ordinates)
       ) sp
WHERE  sp.start_point_index = 2


这两个输出:
| START_POINT_Y |
| ------------ |
| 2 |
| 6 |
| 12 |

应该可以,但没有:

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 column_value
         FROM   (
           select column_value, ROWNUM AS rn
           from   table(c.shape.sdo_ordinates) 
           WHERE  ROWNUM <= 2
         )
         WHERE rn = 2
       ) AS startpoint_y
from   cte c


和/或

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 column_value
         from   table(c.shape.sdo_ordinates) 
         OFFSET 1 ROW FETCH NEXT 1 ROW ONLY
       ) AS startpoint_y
from   cte c


两者都应该工作,但输出:
| STARTPOINT_Y |
| ------------ |
| 2 |
| 2 |
| 2 |

pkbketx9

pkbketx92#

你确实得到了问题的帮助,最好是摆脱这里的rownum-filter,但我猜你仍然错过了答案,为什么rownum = 1完成了这项工作,而rownum = 2没有。
请注意:在Oracle中,你永远不能要求rownum = 2或类似rownum > 2的值。很久以前我读过一个关于这个问题的解释,我不能再给予你解释了,但据我所知,这与“rownum”的求值时间有关。如果你不想让rownum = 1并过滤掉它,那么你永远不会有rownum = 2,这是我脑海中的缩写形式。
如果你将来真的需要处理类似的东西,你可以使用row_number()函数。

tf7tbtn2

tf7tbtn23#

下面是@MTO的第二个查询的通用版本。它将 * 所有 * 坐标作为行,而不仅仅是startpoint_y
或横向交叉接合(或横向应用):

  • (为了清晰起见,我修改了原始问题的样本数据。)*
with cte as (
  select 'A' as line_id, sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(101,102, 103,104                  )) shape from dual union all
  select 'B' as line_id, sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(105,106, 107,108, 109,110         )) shape from dual union all
  select 'C' as line_id, sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(111,112, 113,114, 115,116, 117,118)) shape from dual
)
select 
    cte.line_id,
    v.ordinate_index,
    v.ordinate_val
from   
    cte
cross join lateral (         --CROSS APPLY works too
                    select 
                        rownum as ordinate_index,
                        column_value as ordinate_val 
                    from   
                        table((shape).sdo_ordinates)
                    ) v
--where
    --ordinate_index = 1 --startpoint_x    
    --ordinate_index = 2 --startpoint_y
    --ordinate_index = (sdo_util.getnumvertices(cte.shape)*2) -1 --endpoint x; assumes each vertex only has 2 dimensions (is 2d and not LRS)
    --ordinate_index = (sdo_util.getnumvertices(cte.shape)*2)    --endpoint y; assumes each vertex only has 2 dimensions (is 2d and not LRS)

个字符

相关问题