对于这类问题,最有效的方法是使用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元素,其中每个元素包含一对rowid(表中行的物理标识符),称为ROWID1和ROWID2,它指向交互路段的几对。
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选项。
[不良习惯踢:使用旧式JOIN](http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/bad-habits-to-kick-using-old-style-连接。aspx) - 在ANSI - ** 92 ** SQL标准(**超过20年前的**)中,旧式*逗号分隔的表*样式列表被替换为* proper * ANSI'JOIN'语法并且不鼓励使用它 –