Оператор пространственных данных Oracle — SDO_nn — никаких результатов для sdo_num_res = 1 не получено

Я использую оператор SDO_NN, чтобы найти ближайший к зданию гидрант.

Строительство:

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

Гидрант:

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

Я правильно настроил пространственные индексы для building.shape и запускаю запрос, чтобы получить ближайший гидрант к зданию «Мотель».

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';

Вот проблема:

Когда я устанавливаю параметр sdo_num_res=1, я получаю ноль кортежей. И когда я делаю sdo_num_res=2, я получаю один кортеж.

В чем причина странного поведения?

Примечание. Я получаю нулевые строки только при building.name= 'Motel', для всех остальных кортежей я получаю 1 строку, когда sdo_num_res = 1

Изменить: вставить запросы

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));

person Kalyanaraman Santhanam    schedule 08.03.2013    source источник
comment
Не могли бы вы опубликовать несколько примеров фигур (например, одну успешную комбинацию здания и гидранта и неудачную комбинацию, которая вызывает вашу проблему)? На этот вопрос будет сложно ответить, не имея возможности воспроизвести проблему. Кроме того, было бы полезно знать, какой выпуск Oracle вы используете (исправления пространственных ошибок появляются в большинстве выпусков).   -  person Ben    schedule 08.03.2013
comment
добавлены вставки для столов   -  person Kalyanaraman Santhanam    schedule 09.03.2013
comment
Я не могу воспроизвести эту проблему (см. SQLFiddle: sqlfiddle.com/#!4/9ce47 /14). Возможно, у вашего пространственного индекса есть проблемы, я предлагаю удалить его и перестроить.   -  person Ben    schedule 11.03.2013
comment
Кроме того, ваш синтаксис немного сомнителен - вы, кажется, конвертируете свою одиночную координату гидранта в недопустимый одноточечный многоугольник для сравнения - вы уверены, что это то, что вы хотели сделать? Примечание. Исправление этого не меняет результат для меня.   -  person Ben    schedule 11.03.2013
comment
@ben: я пытаюсь найти ближайший гидрант (точка) к зданию (многоугольник)   -  person Kalyanaraman Santhanam    schedule 11.03.2013
comment
Проверьте свой синтаксис, вы конвертируете точку в недопустимую геометрию многоугольника - 2003 вместо 2001. Это не меняет результат, но я полагаю, что это не ваше намерение. На этот вопрос нельзя ответить как есть, потому что он отлично работает для меня. Может быть, больше данных вызовет проблему?   -  person Ben    schedule 11.03.2013


Ответы (2)


Для выполнения пространственных сравнений между точкой и многоугольником SDO_GEOMETRY определяется с помощью SDO_SRID=2001, а центр устанавливается на SDO_POINT_TYPE->, который мы хотим сравнить.

MDSYS.SDO_GEOMETRY(2001, NULL, SDO_POINT_TYPE(-79, 37, NULL), NULL, NULL)
person Kalyanaraman Santhanam    schedule 13.04.2013

Прежде всего, ваш запрос не делает того, о чем вы говорите: он на самом деле возвращает ближайшее здание под названием «Мотель» из любого из ваших гидрантов. Чтобы сделать то, что вы хотите (то есть наоборот), вам нужно изменить порядок аргументов на SDO_NN: все пространственные операторы ищут первый аргумент, используя значение второго аргумента.

Тогда вставка в вашу таблицу HYDRANTS неверна:

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

Объект SDO_POINT_TYPE не предназначен для использования таким образом: он используется только внутри типа SDO_GEOMETRY. Правильный способ таков:

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

И, конечно же, вам необходимо соответствующим образом изменить определение таблицы.

Тогда ваше здание тоже создается неправильно: многоугольник должен всегда замыкаться, т.е. последняя точка должна совпадать с первой точкой. Таким образом, правильная форма должна быть такой:

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)));

Вот полный пример:

Создайте таблицы:

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

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

Заполните таблицы:

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;

Подтвердите правильность геометрии:

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;

Настройте пространственные метаданные и создайте пространственные индексы:

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;

Теперь попробуйте правильно написанный запрос:

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';

который возвращает:

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

1 row selected.
person Albert Godfrind    schedule 16.05.2014