You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server中STContains等地理函数返回错误结果求助

问题描述

我用SQL Server存储客户经纬度信息,通过Leaflet在地图上展示;同时用Leaflet绘制城市区域多边形,将其以geography类型存储在另一张SQL表中。我编写了如下SQL查询用于判断客户是否位于某一区域(多边形)内,但始终得到错误结果。

我的SQL查询代码
DECLARE @latitude DECIMAL(25,18);
DECLARE @longitude DECIMAL(25,18);
DECLARE @customerId BIGINT;
DECLARE @geographicalAreaId INT;
DECLARE @coordinates GEOGRAPHY;

DECLARE @isInsideArea BIT;

declare @insideCOUNT int;
SET @insideCOUNT=0;

DECLARE @point geography;
DECLARE @polygon geography;

DECLARE getCustomerGeo_CSR CURSOR FAST_FORWARD READ_ONLY 
FOR

    SELECT DISTINCT Fk_CustomerId,ca.Latitude,ca.Longitude FROM Tbl_CustomerAddresses ca
        WHERE ca.Latitude IS NOT NULL AND ca.Longitude IS NOT NULL;

OPEN getCustomerGeo_CSR; 
FETCH NEXT
FROM getCustomerGeo_CSR
INTO @customerId,@latitude, @longitude

WHILE @@FETCH_STATUS = 0
BEGIN

SET @point = geography::Point(cast(@latitude as float), cast(@longitude as float), 4326);

    DECLARE getGeoArea_CSR CURSOR FAST_FORWARD READ_ONLY 
    FOR
        SELECT ga.GeographicalAreaId,ga.Coordinates               
        FROM   Tbl_GeographicalAreas ga         
    
    OPEN getGeoArea_CSR; 
    FETCH NEXT
    FROM getGeoArea_CSR
    INTO @geographicalAreaId, @coordinates

    WHILE @@FETCH_STATUS = 0
    BEGIN
        
        SET @polygon = geography::STGeomFromText((SELECT Coordinates FROM Tbl_GeographicalAreas WHERE GeographicalAreaId = @geographicalAreaId).STAsText(),4326);


        IF @polygon.STContains(@point) = 1
        BEGIN
            SET @insideCOUNT = @insideCOUNT+1;
        END
        
         FETCH NEXT
         FROM getGeoArea_CSR
         INTO @geographicalAreaId, @coordinates
    END
    CLOSE getGeoArea_CSR;
    DEALLOCATE getGeoArea_CSR;
    

    FETCH NEXT
    FROM getCustomerGeo_CSR
    INTO @customerId,@latitude, @longitude
END
CLOSE getCustomerGeo_CSR;
DEALLOCATE getCustomerGeo_CSR;

print @insideCOUNT;
示例多边形数据
POLYGON ((46.389019 38.033642, 46.388397 38.029045, 46.386788 38.027253, 46.383269 38.024701, 46.37872 38.021252, 46.375308 38.020238, 46.374493 38.021861, 46.375351 38.023179, 46.37445 38.02487, 46.37327 38.025478, 46.371167 38.026543, 46.368678 38.026205, 46.367347 38.02727, 46.364343 38.028318, 46.367648 38.030076, 46.368442 38.030329, 46.3696 38.030329, 46.370029 38.030769, 46.370716 38.032036, 46.371725 38.034014, 46.372476 38.035298, 46.372626 38.035772, 46.372755 38.036819, 46.372819 38.037749, 46.373119 38.038814, 46.373441 38.039219, 46.376252 38.03785, 46.378098 38.037259, 46.380415 38.036853, 46.384835 38.036025, 46.386852 38.035079, 46.387968 38.034301, 46.388805 38.033946, 46.389019 38.033642, 46.389019 38.033642))
问题排查与修复

1. 经纬度顺序不匹配(核心错误)

Leaflet输出的坐标顺序是经度在前,纬度在后,但你创建点时用了geography::Point(纬度, 经度),导致点与多边形的坐标逻辑完全错位,这是判断结果错误的主要原因。

修复:交换经纬度顺序创建点:

SET @point = geography::Point(cast(@longitude as float), cast(@latitude as float), 4326);

2. 多边形方向问题

SQL Server的geography类型要求多边形顶点按逆时针方向排列(针对WGS84坐标系4326),如果方向错误,STContains会误判点在多边形外部。可以用ReorientObject()修正:

SET @polygon = @polygon.ReorientObject();

3. 冗余查询与游标优化

  • 内部游标中已经获取了@coordinates,无需重复查询表,直接使用即可:
    SET @polygon = @coordinates; -- 已为geography类型,无需转文本解析
    
  • 嵌套游标性能极差,建议换成集合查询替代:
    SELECT COUNT(*)
    FROM Tbl_CustomerAddresses ca
    CROSS JOIN Tbl_GeographicalAreas ga
    WHERE ca.Latitude IS NOT NULL 
      AND ca.Longitude IS NOT NULL
      AND ga.Coordinates.STContains(
            geography::Point(cast(ca.Longitude as float), cast(ca.Latitude as float), 4326)
          ) = 1;
    

内容的提问来源于stack exchange,提问作者Behnam Faghih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 17:40:11