对于这类问题,最有效的方法是使用 SDO_JOIN() 过滤器。它旨在使用空间索引有效地将空间上的许多对象与许多其他对象匹配。
我假设您的表格如下所示:
create table ottawacollectors (
road_id number,
segment_id number,
road_name varchar2(30),
geometry sdo_geometry,
primary key (road_id, segment_id)
);
它包含路段。每个路段由道路标识符和路段标识符标识。
下面创建新表 INTERSECTIONS,其中每个交叉口都包含一行,即每当两个路段交互时。交点被计算为几何点。每行包含每个路段的标识符(道路标识符和路段标识符)以及每条道路的名称。
create table intersections as
select a.road_id road_id_1, a.segment_id segment_id_1, a.road_name road_name_1,
b.road_id road_id_2, b.segment_id segment_id_2, b.road_name road_name_2,
sdo_geom.sdo_intersection (
a.geometry, b.geometry, 0.05
) intersection_point
from ottawacollectors a,
ottawacollectors b,
table (
sdo_join(
'OTTAWACOLLECTORS','GEOMETRY',
'OTTAWACOLLECTORS','GEOMETRY',
'MASK=ANYINTERACT'
)
) j
where a.rowid = j.rowid1
and b.rowid = j.rowid2
and j.rowid1 > j.rowid2;
一些解释:
SDO_JOIN()
是一个“表”函数。它采用两个输入表的名称(表名称和几何列的名称)和一个匹配条件 - 这里是“ANYINTERACT”,表示任何类型的交互:段可能交叉或只是相互接触。
- 它返回一个 VARRAY 元素,其中每个元素包含一对名为 ROWID1 和 ROWID2 的 rowid(表中行的物理标识符),它们指向一对相互作用的路段。
- 构造函数对该
TABLE()
数组进行强制转换,使其看起来像一个常规表,从而可以轻松地将其嵌入到关系查询中。该“虚拟”表在查询中称为 J。
- 该查询还会读取该
OTTAWACOLLECTORS
表两次(如您的示例中)。它将它们与TABLE()
结果连接起来:J.ROWID1=A.ROWID AND J.ROWID2=B.ROWID
J.ROWID1>J.ROWID2
过滤器可以消除不需要的结果。假设路段 A 和 B 相交。SDO_JOIN 将返回 4 种组合:(A,B),还有 (B,A) 以及 (A,A) 和 (B,B),因为一个段显然与自身相交!比较rowid的目的是只保留(A,B)或(B,A)之一。
- 选择列表包括两个段的完整标识符、它们的名称以及它们的交点(
SDO_GEOM.SDO_INTERSECTION()
在您的示例中使用类似计算)。
- 最后将结果写入表中
请注意,此查询不会立即返回结果:可能需要几分钟才能完成,具体取决于您需要处理的路段数量,当然也取决于您运行它的硬件。如果您在 Oracle 12c(12.1.0.1 或 12.1.0.2)上运行它并且您拥有 Oracle Spatial 的正确许可,那么请确保您已打开 Vector Performance Accelerator 选项。