Oracle Spatial - SDO_BUFFER 不起作用?

Oracle Spatial - SDO_BUFFER does not work?

我有一个 table,它有 SDO_Geometries,我查询所有几何图形以找到它们的起点和终点,然后我将这些点插入另一个名为 ORAHAN 的 table。现在我的主要目的是对于 orahan 中的每个点,我必须在为点提供 2 cm 缓冲区时发现它是否与 orahan 中的另一个点相交。 因此,我使用 Relate 和 Bufer 函数编写了一些 pl sql,但是当我检查 Map Info 中的一些记录时,我看到在其自身 1 厘米区域内有一些点,但在称为 ORAHANCROSSES 的交叉点 table 中没有记录。 是我用错了这些功能还是怎么的?

注意:我使用的是 Oracle 数据库 11g 企业版 11.2.0.1.0 版 - 64 位生产版和 PL/SQL 版本 11.2.0.1.0 - 和 SDO_PACKAGE

ORAHAN 有大约 40 万条记录。(点和其他列。)

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 地图图像,显示了彼此接近约 1 厘米的 3 个点。但是在orahancrosses中没有匹配这3个的记录。

注:0,00001000km等于1cm

奥拉汉元数据:

select * from user_sdo_geom_metadata where table_name = 'ORAHAN';

和暗信息:

你的数据坐标系是什么?而且,最重要的是,您在元数据中设置了什么 容差

其他一些评论:

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) 正如所写,2 厘米以内的一对点 A 和 B 将被 return 编辑两次:一次作为 (A,B),另一次作为 (B,A)。为了避免这种情况(并且只有 return 一种情况),然后像这样编写查询:

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 企业版的许可证并且您的硬件具有适当的容量(内核数),那么并行性可以减少运行时间。

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 (=50cm) 传递以生成半径为 0.02 (2cm) 的缓冲区。效果是产生的缓冲区有效地溶解到点本身中。

例如公差为 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'