在空间数据库中,ST_Contains() 和 ST_Within() 是两个非常常用且密切相关的空间关系函数,都用于判断一个几何对象是否在另一个几何对象的内部。然而,它们在拓扑关系的定义上存在细微但关键的区别,理解这些差异对于准确地进行空间查询至关重要。
1. ST_Contains(A, B) 的定义与特性
ST_Contains(geometry A, geometry B) 函数判断几何 A 是否“包含”几何 B。
定义: 如果几何 B 的所有点都位于几何 A 的内部,并且几何 B 的任何点都不在几何 A 的外部,则 ST_Contains(A, B) 返回 TRUE。
边界排除: ST_Contains() 的一个关键特性是它强调严格的内部包含。这意味着如果 B 仅仅是接触 A 的边界,或者 B 的部分在 A 的边界上,ST_Contains(A, B) 可能会返回 FALSE。具体来说,OGC 标准中的DE-9IM 模型定义了 ST_Contains() 为:A 的内部与 B 的内部相交,并且 A 的内部与 B 的边界相交,同时 B 的内部和边界与 A 的外部不相交。
非对称性: 这是一个非对称的关系。如果 A 包含 B,并不意味着 B 包含 A。
示例:
一个省份多边形严格包含一个城市多边形。
一个房屋多边形严格包含它内部的一个点。
线不会 Contains 一个与它部分重叠的面。
点不会 Contains 任何其他几何对象(除非它本身是GeometryCollection且包含一个点)。
2. ST_Within(A, B) 的定义与特性
ST_Within(geometry A, geometry B) 函数判断几何 A 是否 特殊数据库 “在”几何 B 内部。
定义: 如果几何 A 的所有点都位于几何 B 的内部,并且几何 A 的任何点都不在几何 B 的外部,则 ST_Within(A, B) 返回 TRUE。
关系: ST_Within(A, B) 在语义上等价于 ST_Contains(B, A)。换句话说,如果 A 在 B 内部,那么 B 就包含 A。它们是互逆的关系。
边界排除: 同样,ST_Within() 也强调严格的内部关系。如果 A 仅仅接触 B 的边界,它通常不会被认为是 Within B。
示例:
一个城市多边形严格 Within 一个省份多边形。
一个点严格 Within 一个房屋多边形。
3. 主要区别与选择考量
特性 ST_Contains(A, B) ST_Within(A, B)
语义 A 包含 B A 在 B 内部
等价关系 等价于 ST_Within(B, A) 等价于 ST_Contains(B, A)
边界处理 严格内部包含,如果 B 接触 A 边界可能为 FALSE 严格内部包含,如果 A 接触 B 边界可能为 FALSE
谁是“大”对象 A 通常是“容器”或“更大”的几何对象 B 通常是“容器”或“更大”的几何对象
常用场景 查找某个区域内包含哪些其他对象 查找某个对象属于哪个外部区域
Export to Sheets
选择考量:
哪个是容器,哪个是被包含者? 如果你想从逻辑上表达“容器包含内容”,就用 ST_Contains(容器, 内容)。如果你想表达“内容在容器内”,就用 ST_Within(内容, 容器)。
边界条件: 如果你需要包含边界接触的情况,那么 ST_Intersects(A, B) 可能是更合适的选择,因为它更宽松。例如,一个点在多边形的边界上,ST_Contains() 和 ST_Within() 可能返回 FALSE,而 ST_Intersects() 会返回 TRUE。
示例:
查找所有位于某个行政区划内的咖啡馆:
SQL
-- 推荐使用ST_Within,因为咖啡馆在行政区划内部
SELECT c.cafe_name FROM cafes c, administrative_regions ar
WHERE ST_Within(c.geom, ar.geom) AND ar.region_name = 'Downtown';
查找包含某个学校的行政区划:
SQL
-- 推荐使用ST_Contains,因为行政区划包含学校
SELECT ar.region_name FROM administrative_regions ar, schools s
WHERE ST_Contains(ar.geom, s.geom) AND s.school_name = 'Central High';
理解 ST_Contains() 和 ST_Within() 的细微差异,有助于编写出更准确、更符合逻辑的空间查询语句。