Oracle Spatial - SDO_BUFFER не работает?

У меня есть таблица с SDO_Geometries, и я запрашиваю все геометрии, чтобы найти их начальную и конечную точку, а затем вставляю эти точки в другую таблицу с именем ORAHAN. Теперь моя главная цель - для каждой точки в orahan, я должен найти, пересекается ли она с другой точкой в ​​orahan, когда дается 2-сантиметровый буфер для точек. Поэтому я пишу некоторые pl sql, используя функции Relate и Bufer, но когда я проверял некоторые записи в Map Info, я увидел, что есть точки в пределах 1 см от себя, но нет записи в таблице пересечений под названием ORAHANCROSSES. Я неправильно использую эти функции или как?

Примечание. Я использую Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64-разрядная версия и PL/SQL Release 11.2.0.1.0 - и SDO_PACKAGE.

ORAHAN насчитывает около 400 тысяч записей.(Точки и другие столбцы.)

declare
BEGIN
 for curs in (select * from ORAHAN t) loop
   for curs2 in (select *
                   from ORAHAN t2
                  where SDO_RELATE(t2.geoloc,SDO_GEOM.SDO_BUFFER(curs.geoloc,0.02,0.5) , 
                  'mask=ANYINTERACT') = 'TRUE'
                    and t2.mi_prinx <> curs.mi_prinx) loop                    
     Insert INTO ORAHANCROSSES
     values
       (curs.Mip, curs.Startmi, curs2.Mip, curs2.Startmi);
     commit;
   end loop;
 end loop;
END;

И это изображение карты MapInfo, которое показывает 3 точки, которые находятся близко друг к другу примерно на 1 сантиметр. Но в orahancrosses нет записей, соответствующих этим 3.

Примечание: 0,00001000 км равен 1 см введите описание изображения здесь

Орахан Метаданные:

select * from user_sdo_geom_metadata where table_name = 'ORAHAN';

введите описание изображения здесь

И Диминфо:

введите описание изображения здесь

1 ответ

Решение

Какова система координат ваших данных? И, самое главное, какую терпимость вы установили в своих метаданных?

Некоторые другие комментарии:

1) Не используйте отношение с буферным подходом. Просто используйте подход на расстоянии.

2) Вам не нужен цикл PL/SQL для такого запроса, просто используйте простой CTAS:

create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from orahan c1, orahan c2
where sdo_within_distance (c2.geoloc, c1.geoloc, 'distance=2 unit=cm') = 'TRUE'
and c2.mi_prinx <> c1.mi_prinx;

3) Как написано, пары точек A и B, которые находятся в пределах 2 см, будут возвращены дважды: один раз как (A,B) и еще раз как (B,A). Чтобы избежать этого (и вернуть только один из случаев), напишите запрос следующим образом:

create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from orahan c1, orahan c2
where sdo_within_distance (c2.geoloc, c1.geoloc, 'distance=2 unit=cm') = 'TRUE'
and c1.rowid < c2.rowid;

3) Обработка количества упомянутых вами точек (400000+) должна выполняться лучше с использованием техники SDO_JOIN, например:

create table orahancrosses as
select c1.mip mip_1, c1.startmi startmi_1, c2.mip mip_2, c2.startmi startmi_2
from  table (
        sdo_join (
          'ORAHAN','GEOLOC',
          'ORAHAN','GEOLOC',
          'DISTANCE=2 UNIT=CM'
        )
      ) j,
      orahan c1, 
      orahan c2
where j.rowid1 < j.rowid2
and c1.rowid = j.rowid1
and c2.rowid = j.rowid2;

Это, вероятно, все еще займет время для обработки - в зависимости от мощности вашего сервера базы данных. Если у вас есть лицензии на Oracle Enterprise Edition, а ваше оборудование имеет надлежащую емкость (число ядер), то параллелизм может сократить затраченное время.

4) Вы говорите, что используете Oracle 11g. Какая точная версия? Версия 11.2.0.4 - это версия терминала для 11gR2. Все, что старше, больше не поддерживается. К настоящему времени вы действительно должны быть на 12cR1 (12.1.0.2). Основное преимущество 12.1.0.2 в вашем случае - функция Vector Performance Accelerator, которая ускоряет ряд пространственных функций и операторов (только если у вас есть соответствующие лицензии Oracle Spatial - она ​​недоступна с бесплатной функцией Oracle Locator).

======================================

Используя две точки в вашем примере. Давайте посчитаем расстояние:

select sdo_geom.sdo_distance(
  sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null), 
  sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.07336716,null),null,null),
  0.005
) distance
from dual;


  DISTANCE
----------
 .01000197

1 row selected.

Обратите внимание, я не указываю SRID. Предполагая, что координаты выражены в метрах, расстояние между ними действительно немного больше 1 см.

======================================

Как вы заметили, причина, по которой ваш оригинальный синтаксис не работает, заключается в допустимом отклонении, которое вы указываете для вызова SDO_BUFFER(). Вы передаете его как 0,5 (=50 см), чтобы получить буфер с радиусом 0,02 (2 см). В результате получаемый буфер эффективно растворяется в самой точке.

Например, с допуском 0,5:

select sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.5) from dual;

Производит:

SDO_GEOMETRY(2001, NULL, SDO_POINT_TYPE(521554.782, 4230983.08, NULL), NULL, NULL)

При допуске 0,005:

select sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.005) from dual;

Вы получаете правильный буфер:

SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 2), SDO_ORDINATE_ARRAY(521554.782, 4230983.06, 521554.802, 4230983.08, 521554.782, 4230983.1, 521554.762, 4230983.08, 521554.782, 4230983.06))

И очень близкая точка теперь совпадает с этим буфером:

select sdo_geom.relate(
  sdo_geom.sdo_buffer(sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.08336913,null),null,null),0.02,0.005),
  'determine',
  sdo_geometry (2001,null,sdo_point_type(521554.782174622,4230983.07336716,null),null,null),
  0.005
) relation
from dual;

RELATION
------------------------- 
CONTAINS

1 row selected.

======================================

Теперь тот факт, что ваши данные не имеют правильного явного SRID, означает, что использование явных единиц измерения или измерений на расстоянии не будет работать. Поскольку база данных не знает, в какой системе координат находятся ваши данные, она не знает, как определить, что две точки меньше установленного числа см или м друг от друга. Все, что вы можете сделать, это предположить, что координаты указаны в метрах.

Поэтому в приведенных выше примерах замените 'DISTANCE=2 UNIT=CM' с 'DISTANCE=0.02'

Другие вопросы по тегам