Frage

I am using SDO_NN operator to find the nearest hydrant next to a building.

Building:

CREATE TABLE  "BUILDINGS" 
(   
"NAME" VARCHAR2(40), 
"SHAPE" "SDO_GEOMETRY") 

Hydrant:

CREATE TABLE  "HYDRANTS" 
   (    "NAME" VARCHAR2(10), 
"POINT" "SDO_POINT_TYPE"
  );

I have setup spatial indexes properly for buildings.shape and I run the query to get the nearest hydrant to the building 'Motel'

select b1.name as name, h.point.x as x, h.point.y as y  from buildings b1, hydrants h where  b1.name ='Motel'  and
                    SDO_nn( b1.shape, MDSYS.SDO_GEOMETRY(2003,NULL, NULL,SDO_ELEM_INFO_ARRAY(1,1003,1),
                            SDO_ORDINATE_ARRAY( h.point.x,h.point.y)), 'sdo_num_res=1')= 'TRUE';

Here's the problem:

When I set the parameter sdo_num_res=1, I get zero tuples. And when I make sdo_num_res=2, I get one tuple.

What is the reason for the weird behavior ?

Note: I am getting zero rows only when building.name= 'Motel', for all other tuples I am getting 1 row when sdo_num_res = 1

Edit: Insert queries

Insert into buildings (NAME,SHAPE) values ('Motel',MDSYS.SDO_GEOMETRY(2003,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1),MDSYS.SDO_ORDINATE_ARRAY(564,425,585,436,573,458,552,447)));

Insert into hydrants  (name,POINT) values ('p57',MDSYS.SDO_POINT_TYPE(589,448,0));
War es hilfreich?

Lösung

To perform spatial comparisons between a point to a polygon, the SDO_GEOMETRY is defined with SDO_SRID=2001 and center set to a SDO_POINT_TYPE-> which we want to compare.

MDSYS.SDO_GEOMETRY(2001, NULL, SDO_POINT_TYPE(-79, 37, NULL), NULL, NULL)

Andere Tipps

First of all, your query does not do what you say it does: it actually returns the nearest building called "Motel" from any of your hydrants. To do what you want (i.e. the opposite) you need to reverse the order of the arguments to SDO_NN: all spatial operators search the first argument, using the value of the second argument.

Then the insert into your HYDRANTS table is wrong:

Insert into hydrants  (name,POINT) values ('p57',MDSYS.SDO_POINT_TYPE(589,448,0));

The SDO_POINT_TYPE object is not designed to be used that way: it is only used inside the SDO_GEOMETRY type. The proper way is this:

insert into hydrants (name,POINT) values ('p57',sdo_geometry(2001, null, SDO_POINT_TYPE(589,448,null), null, null));

And of course you need to change your table definition accordingly.

Then your building is also incorrectly created: a polygon must always close, i.e. the last point must be the same as the first point. So the proper shape should be like this:

insert into buildings (NAME,SHAPE) values ('Motel', SDO_GEOMETRY(2003,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY(564,425,585,436,573,458,552,447,564,425)));

Here is the full example:

Create the tables:

create table buildings (
  name varchar2(40) primary key,
  shape sdo_geometry
);

create table hydrants(
  name varchar2(10) primary key, 
  point sdo_geometry
);

Populate the tables:

insert into buildings (NAME,SHAPE) values ('Motel', SDO_GEOMETRY(2003,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY(564,425,585,436,573,458,552,447,564,425)));
insert into hydrants (name,POINT) values ('p57',sdo_geometry(2001, null, SDO_POINT_TYPE(589,448,null), null, null));
commit;

Confirm that the geometries are all correct:

select name, sdo_geom.validate_geometry_with_context (point, 0.05) from hydrants;
select name, sdo_geom.validate_geometry_with_context (shape, 0.05) from buildings;

Setup spatial metadata and create spatial indexes:

insert into user_sdo_geom_metadata (table_name, column_name, diminfo, srid)
values (
  'BUILDINGS',
  'SHAPE',
  sdo_dim_array (
    sdo_dim_element ('X', 0,1000,0.05),
    sdo_dim_element ('Y', 0,1000,0.05)
  ),
  null
);
commit;

create index buildings_sx on buildings (shape)
  indextype is mdsys.spatial_index;

insert into user_sdo_geom_metadata (table_name, column_name, diminfo, srid)
values (
  'HYDRANTS',
  'POINT',
  sdo_dim_array (
    sdo_dim_element ('X', 0,1000,0.05),
    sdo_dim_element ('Y', 0,1000,0.05)
  ),
  null
);
commit;

create index hydrants_sx on hydrants (point)
  indextype is mdsys.spatial_index;

Now Try the properly written query:

select h.name, h.point.sdo_point.x as x, h.point.sdo_point.y as y  
from buildings b, hydrants h 
where b.name ='Motel' 
and sdo_nn(h.point, b.shape, 'sdo_num_res=1')= 'TRUE';

which returns:

NAME                      X          Y
---------------- ---------- ----------
p57                     589        448

1 row selected.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top