3

Oracle 18c:

I can extract the startpoint X coordinate from an SDO_GEOMETRY using SHAPE.SDO_ORDINATES(1) in a custom PL/SQL function:

with 
function startpoint_x(shape in sdo_geometry) return number 
is
begin
  return 
  shape.sdo_ordinates(1); 
end;

select
  startpoint_x(shape) as startpoint_x
from
  (select sdo_geometry('linestring(1 2, 3 4, 5 6)') as shape 
   from dual)

STARTPOINT_X
------------
           1

But if I try do that purely in an SQL query, I get an error:

select
  (shape).sdo_ordinates(1) as startpoint_x
from
  (select sdo_geometry('linestring(1 2, 3 4, 5 6)') as shape 
   from dual)

ORA-00904: "MDSYS"."SDO_GEOMETRY"."SDO_ORDINATES": invalid identifier

For what it's worth, if I were to remove the (1) and instead select the entire sdo_ordinates attribute, then that would work:

select
  (shape).sdo_ordinates as ordinates 
from
  (select sdo_geometry('linestring(1 2, 3 4, 5 6)') as shape 
   from dual)

ORDINATES
------------------------
SDO_ORDINATE_ARRAY(1, 2)

db<>fiddle

But of course, that's not what I want. I want to get the startpoint X coordinate as a number.

Why does SHAPE.SDO_ORDINATES(1) work in PL/SQL, but not in an SQL query?


Somewhat related: Get X & Y coordinates from GEOM_SEGMENT_START_PT()

User1974
  • 276
  • 1
  • 17
  • 63

3 Answers3

1

Why does SHAPE.SDO_ORDINATES(1) work in PL/SQL, but not in an SQL query?

Because the syntax of extracting collection elements by index is not supported in SQL. It is not just SDO objects but any collection:

SELECT SYS.ODCIVARCHAR2LIST('a', 'b', 'c')(1) FROM DUAL;

Outputs:

ORA-03001: unimplemented feature

and:

SELECT l.list(1)
FROM   (SELECT SYS.ODCIVARCHAR2LIST('a', 'b', 'c') AS list FROM DUAL) l;

Outputs:

ORA-00904: "L"."LIST": invalid identifier

(Which, I think means that it is trying to parse it as a function but the error message is less helpful/obvious than the previous one.)


There are methods of getting the value but it is more complicated as you need to dereference the entire collection using a table collection expression and then filter to get the desired row:

SELECT (
         SELECT COLUMN_VALUE
         FROM   TABLE(s.shape.sdo_ordinates)
         FETCH FIRST ROW ONLY
       ) as startpoint_x
FROM  (
  select sdo_geometry('linestring(1 2, 3 4, 5 6)') as shape from dual
) s

db<>fiddle here

MT0
  • 143,790
  • 11
  • 59
  • 117
  • Thanks! FYI, I submitted an idea to Oracle: [Support extracting collection elements by index in SQL](https://community.oracle.com/tech/developers/discussion/4499553/support-extracting-collection-elements-by-index-in-sql/p1?new=1). Hopefully that idea is sensible? – User1974 Jun 10 '22 at 08:37
  • You might find this technique interesting: `json_value((shape).Get_GeoJson(),'$.coordinates[0][0]')`. https://community.oracle.com/tech/apps-infra/discussion/comment/16840191/#Comment_16840191 – User1974 Jun 30 '22 at 17:26
1

My guess is that varrays and table collections have to be treated as tables, and SQL (3) doesn't support them in native SQL.

Simon Greener
  • 425
  • 2
  • 5
0

See if such a workaround helps ...

This is what you have and it works:

SQL> select
  2    (shape).sdo_ordinates as ordinates
  3  from
  4    (select sdo_geometry('linestring(1 2, 3 4, 5 6)') as shape
  5     from dual);

ORDINATES
------------------------------------------------------------
SDO_ORDINATE_ARRAY(1, 2, 3, 4, 5, 6)

This is what you tried, but it doesn't work:

SQL> select
  2    (shape).sdo_ordinates(1) as startpoint_x
  3  from
  4    (select sdo_geometry('linestring(1 2, 3 4, 5 6)') as shape
  5     from dual);
  (shape).sdo_ordinates(1) as startpoint_x
                       *
ERROR at line 2:
ORA-00904: "MDSYS"."SDO_GEOMETRY"."SDO_ORDINATES": invalid identifier

And this is a workaround:

SQL> select
  2    sdo_geom.sdo_min_mbr_ordinate(shape, 1) as startpoint_x
  3  from
  4    (select sdo_geometry('linestring(1 2, 3 4, 5 6)') as shape
  5     from dual);

STARTPOINT_X
------------
           1

SQL>
Littlefoot
  • 131,892
  • 15
  • 35
  • 57
  • I think it might just be a coincidence that MBR (minimum bounding rectangle) works in this case, for this test data. I suspect it wouldn’t provide the right results for real-world geometries. – User1974 Jun 12 '22 at 20:10