-- 範例一:找出在特定區域內且符合特定條件的點位 SELECT p.* FROM Points p JOIN Zones z ON z.geometry.STContains(p.geometry) =1 WHERE z.ZoneName ='特定區域' AND p.Type ='住宅' AND p.Status ='使用中'
-- 範例二:找出在多個區域內的點位並標示區域名稱 -- geometry 為不可比較型別不可放入 GROUP BY;先聚合,再 JOIN 回原表取完整欄位 SELECT p.*, agg.所在區域 FROM Points p JOIN ( SELECT p2.Id, STRING_AGG(z.ZoneName, ',') as 所在區域, COUNT(*) as 區域數 FROM Points p2 JOIN Zones z ON z.geometry.STContains(p2.geometry) =1 GROUPBY p2.Id HAVINGCOUNT(*) >1-- 只保留位於多個區域的點位 ) agg ON agg.Id = p.Id
SELECT p.*, p.geometry.STDistance(@中心點) as 距離 FROM Points p WHERE p.geometry.STIntersects(@緩衝區) =1-- 先走空間索引(bounding box 過濾) AND p.geometry.STDistance(@中心點) <=500-- 再精確篩選 ORDERBY 距離
-- 範例二:計算所有點位兩兩距離 -- ⚠ CROSS JOIN 為 O(n²),資料量大時效能急遽惡化;僅適合小量資料 SELECT p1.Id as 起點ID, p2.Id as 終點ID, p1.geometry.STDistance(p2.geometry) as 距離 FROM Points p1 CROSSJOIN Points p2 WHERE p1.Id < p2.Id -- 避免重複組合 ORDERBY 距離
4. 範圍運算案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-- 範例一:計算多個區域的聯集範圍 -- ⚠ geometry::UnionAggregate() 需要 SQL Server 2012 或以上版本 WITH 合併範圍 AS ( SELECT geometry::UnionAggregate(geometry) as 總範圍 FROM Zones WHERE ZoneType ='服務區' ) SELECT 總範圍, 總範圍.STArea() as 總面積 FROM 合併範圍
-- 範例二:找出兩個區域的重疊部分 SELECT @區域A.STIntersection(@區域B) as 重疊區域, @區域A.STIntersection(@區域B).STArea() as 重疊面積
-- 範例一:從規劃範圍中扣除多個禁制區 WITH 禁制區 AS ( SELECT geometry::UnionAggregate(geometry) as 總禁制區 FROM Zones WHERE ZoneType ='禁制區' ) SELECT @規劃範圍.STDifference(總禁制區) as 可用範圍, @規劃範圍.STDifference(總禁制區).STArea() as 可用面積 FROM 禁制區
-- 範例二:建立緩衝區並找出在緩衝區內的點位 -- ⚠ CROSS APPLY 內的 UnionAggregate 會對 ServicePoints 全表聚合,且對每列 Points 重複執行 -- 資料量大時效能極差。正確作法:先在外部一次算好聯集緩衝區,再做 STContains 過濾 -- 以下僅作示範,生產環境請先 DECLARE @緩衝區聯集 = (SELECT geometry::UnionAggregate(...) FROM ServicePoints WHERE ...) SELECT p.* FROM Points p CROSS APPLY ( SELECT geometry::UnionAggregate(geometry.STBuffer(100)) as 緩衝區 FROM ServicePoints WHERE Type ='服務站' ) buffer WHERE buffer.緩衝區.STContains(p.geometry) =1
-- 範例一:計算各區域內的點位數量 -- geometry 為不可比較型別,不可放入 GROUP BY;先聚合非空間欄位,再 JOIN 回原表取 geometry SELECT z.ZoneName, agg.點位數量, z.geometry.STArea() as 區域面積, agg.點位數量 *1.0/ z.geometry.STArea() as 點位密度 FROM Zones z JOIN ( SELECT z2.ZoneId, COUNT(*) as 點位數量 FROM Zones z2 JOIN Points p ON z2.geometry.STContains(p.geometry) =1 GROUPBY z2.ZoneId ) agg ON agg.ZoneId = z.ZoneId
-- 範例二:計算點位的分佈情況 -- ⚠ 自我 JOIN 為 O(n²);且 WHERE p1.geometry.STDistance(p2.geometry) <= 1000 繞過空間索引 -- 如需處理大量資料,應改為:以 STBuffer(1000) 預先縮小候選集,再計算距離統計 SELECT p1.Id as 中心點ID, COUNT(*) as 周圍點位數量, AVG(p1.geometry.STDistance(p2.geometry)) as 平均距離, MIN(p1.geometry.STDistance(p2.geometry)) as 最短距離, MAX(p1.geometry.STDistance(p2.geometry)) as 最長距離 FROM Points p1 JOIN Points p2 ON p1.Id != p2.Id WHERE p1.geometry.STDistance(p2.geometry) <=1000 GROUPBY p1.Id
7. 資料驗證案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- 範例一:檢查點位是否在合法範圍內 SELECT p.* FROM Points p LEFTJOIN LegalZones z ON z.geometry.STContains(p.geometry) =1 WHERE z.Id ISNULL-- 找出不在任何合法區域內的點位
-- 範例二:檢查兩個點位是否過於接近 SELECT p1.Id as 點位1, p2.Id as 點位2, p1.geometry.STDistance(p2.geometry) as 距離 FROM Points p1 JOIN Points p2 ON p1.Id < p2.Id WHERE p1.geometry.STDistance(p2.geometry) <10-- 距離小於10公尺