Transact SQL geography多边形STContains判断结果异常问题问询
问题原因与解决方案
你的问题核心在于SQL Server geography类型的多边形环方向规则:
- geography基于球面坐标系,多边形的环方向直接决定它代表的区域:
- 逆时针外环对应环内的小区域(即你预期的卢森堡范围)
- 顺时针外环则对应整个地球表面减去环内小区域(相当于“反多边形”)
你自认为是逆时针创建的多边形,但实际点的顺序是顺时针(右上→左上→左下→右下→右上),导致这个多边形实际代表“地球除卢森堡外的所有区域”,所以布鲁塞尔的点也被包含在内,STContains返回true。
解决方法
有两种方式可以修正:
1. 反转点顺序,改为逆时针
调整插入@points表的点顺序,让环按逆时针方向绘制:
declare @points table (locationcode nvarchar(max), latitude real, longitude float, info nvarchar(max), ord int) declare @locationcode nvarchar(max) = 'LUX' insert into @points values ('LUX', 50.264980, 6.650216, 'right top', 1), ('LUX', 49.322218, 6.657984, 'right bottom', 2), ('LUX', 49.307025, 5.430560, 'left bottom', 3), ('LUX', 50.294766, 5.345107, 'left top', 4), ('LUX', 50.264980, 6.650216, 'right top', 5) declare @buildstring nvarchar(max) select @buildstring = coalesce(@buildstring + ', ','') + convert(nvarchar,latitude) + ' ' + convert(nvarchar,longitude) from @points where locationcode = @locationcode order by ord declare @polygon geography = 'POLYGON((' + @buildstring + '))' print 'polygon:' print @polygon.ToString() print @polygon.STIsValid() -- point in polygon coordinates: declare @pointInLatitude float declare @pointInLongitude float declare @pointIn geography -- point out of polygon coordinates: declare @pointOutLatitude float declare @pointOutLongitude float declare @pointOut geography -- +/- center Luxembourg city (Luxembourg): set @pointInLatitude = 49.609133 set @pointInLongitude = 6.136210 set @pointIn = geography::Point(@pointInLatitude, @pointInLongitude, 4326) -- +/- center Brussels city: (Belgium) set @pointOutLatitude = 50.847726 set @pointOutLongitude = 4.349612 set @pointOut = geography::Point(@pointOutLatitude, @pointOutLongitude, 4326) select @polygon.STContains(@pointIn) , @polygon.STContains(@pointOut)
2. 使用ReorientObject()反转多边形环方向
如果不想修改点顺序,可在创建多边形后调用ReorientObject()自动反转环方向:
declare @points table (locationcode nvarchar(max), latitude real, longitude float, info nvarchar(max), ord int) declare @locationcode nvarchar(max) = 'LUX' insert into @points values ('LUX', 50.264980, 6.650216, 'right top', 1), ('LUX', 50.294766, 5.345107, 'left top', 2), ('LUX', 49.307025, 5.430560, 'left bottom', 3), ('LUX', 49.322218, 6.657984, 'right bottom', 4), ('LUX', 50.264980, 6.650216, 'right top', 5) declare @buildstring nvarchar(max) select @buildstring = coalesce(@buildstring + ', ','') + convert(nvarchar,latitude) + ' ' + convert(nvarchar,longitude) from @points where locationcode = @locationcode order by ord declare @polygon geography = 'POLYGON((' + @buildstring + '))' -- 反转环方向,修正多边形代表的区域 set @polygon = @polygon.ReorientObject() print 'polygon:' print @polygon.ToString() print @polygon.STIsValid() -- point in polygon coordinates: declare @pointInLatitude float declare @pointInLongitude float declare @pointIn geography -- point out of polygon coordinates: declare @pointOutLatitude float declare @pointOutLongitude float declare @pointOut geography -- +/- center Luxembourg city (Luxembourg): set @pointInLatitude = 49.609133 set @pointInLongitude = 6.136210 set @pointIn = geography::Point(@pointInLatitude, @pointInLongitude, 4326) -- +/- center Brussels city: (Belgium) set @pointOutLatitude = 50.847726 set @pointOutLongitude = 4.349612 set @pointOut = geography::Point(@pointOutLatitude, @pointOutLongitude, 4326) select @polygon.STContains(@pointIn) , @polygon.STContains(@pointOut)
验证结果
两种方法执行后,STContains(@pointIn)返回1(卢森堡点在多边形内),STContains(@pointOut)返回0(布鲁塞尔点在多边形外),符合预期。
内容的提问来源于stack exchange,提问作者Serge Van Cleynenbreugel
相关产品推荐
相关产品推荐

