-1

Oracle 18c:

Using this sample data:

with data (asset_id, shape) as (
  select 100, sdo_geometry('linestring (10 20, 30 40)')                       from dual union all
  select 200, sdo_geometry('linestring (50 60, 70 80, 90 100)')               from dual union all
  select 300, sdo_geometry('linestring (110 120, 130 140, 150 160, 170 180)') from dual
)
select * from data

  ASSET_ID SHAPE
---------- --------------------
       100 [MDSYS.SDO_GEOMETRY]
       200 [MDSYS.SDO_GEOMETRY]
       300 [MDSYS.SDO_GEOMETRY]

I want to extract the SDO_GEOMETRY line vertices and store them as SDO_GEOMETRY points in SDO_GEOMETRY_ARRAYs.

The result would look like this:

  ASSET_ID  POINT_ARRAY
----------  ------------
       100  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])
       200  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])
       300  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])

Is there a way to convert those lines to points in an array?

User1974
  • 276
  • 1
  • 17
  • 63

1 Answers1

0

Steps:

  1. Inner query: Get point geometries as rows for each vertex in SDO_GEOMETRY line.

  2. Outer query: Collect the points into SDO_GEOMETRY_ARRAY values.

Related:


with data (asset_id, shape) as (
  select 100, sdo_geometry('linestring (10 20, 30 40)')                       from dual union all
  select 200, sdo_geometry('linestring (50 60, 70 80, 90 100)')               from dual union all
  select 300, sdo_geometry('linestring (110 120, 130 140, 150 160, 170 180)') from dual
)
select 
    asset_id,
    cast(collect(shape order by vertex_index) as sdo_geometry_array) as point_array
from
    (
    select 
        d.asset_id,
        vertex_index,
        p.shape
    from   
        data d
    cross join lateral (
        select 
            sdo_util.get_coordinate(d.shape,level) as shape, level as vertex_index
        from   
            dual
        connect by level <= sdo_util.getnumvertices(d.shape)
        ) p
    )    
group by 
    asset_id        
order by
    asset_id

Result:

  ASSET_ID  POINT_ARRAY
----------  ------------
       100  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])
       200  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])
       300  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])

Edit:

An improved version from @MT0:

You can aggregate inside the LATERAL subquery which removes the need to use GROUP BY across the entire result set: db<>fiddle.

WITH data (asset_id, shape) AS (
  select 100, sdo_geometry('linestring (10 20, 30 40)')                       from dual union all
  select 200, sdo_geometry('linestring (50 60, 70 80, 90 100)')               from dual union all
  select 300, sdo_geometry('linestring (110 120, 130 140, 150 160, 170 180)') from dual
)
SELECT asset_id,
       point_array
FROM   data d
       CROSS JOIN LATERAL (
         SELECT CAST(
                  COLLECT(
                    sdo_util.get_coordinate(d.shape,level)
                    ORDER BY LEVEL
                  )
                  AS SDO_GEOMETRY_ARRAY
                ) AS point_array
         FROM   DUAL
         CONNECT BY LEVEL <= sdo_util.getnumvertices(d.shape)
       ) p
ORDER BY
       asset_id

Result:

  ASSET_ID  POINT_ARRAY
----------  ------------
       100  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])
       200  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])
       300  MDSYS.SDO_GEOMETRY_ARRAY([MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY], [MDSYS.SDO_GEOMETRY])
User1974
  • 276
  • 1
  • 17
  • 63
  • 1
    You can aggregate inside the `LATERAL` subquery which removes the need to use `GROUP BY` across the entire result set [db<>fiddle](https://dbfiddle.uk/?rdbms=oracle_21&fiddle=e1b8985b45b07910e2001cc45ab9c3f3) – MT0 Jun 21 '22 at 07:36
  • @MT0 By the way, I noticed in your fiddle that db<>fiddle produced an empty resultset yet again (a db<>fiddle bug). You might be interested in this post of mine in the TopAnswers db<>fiddle community: [Provide tips in db<>fiddle help for returning abstract datatypes (Oracle)](https://topanswers.xyz/fiddle?q=2045). – User1974 Jun 21 '22 at 07:50
  • 1
    Its just a variation on your answer. Feel free to edit it into yours or leave it as a comment. – MT0 Jun 21 '22 at 08:06