對於這類問題,最有效的方法是使用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'語法並且不鼓勵使用它 –