SQL 查询地理信息中指定距离范围内的记录

目标:选取在指定位置1公里范围的记录
测试数据:指定时间范围内,16万记录
跟据测试结果,如果不是需要很高精度,用第一种方法就可以了

方法1:按矩形算
优点:快,缺点:不是圆型的范围,平均执行150ms

DECLARE @GGP_LOCATE_POINT GEOGRAPHY = GEOGRAPHY::Point( 22.26663,113.821256666667, 4326);  
DECLARE @FLT_LONGITUDE   FLOAT,  @FLT_LATITUDE   FLOAT  --纬度
SELECT @FLT_LONGITUDE =113.821256666667, @FLT_LATITUDE =22.26663
SELECT @GGP_LOCATE_POINT.STDistance(GEOGRAPHY::Point([LATITUDE],[LONGITUDE], 4326)) as [验证距离], *  FROM [目标表]
WHERE [ALERT_TIME] BETWEEN '2015-09-08' AND  '2015-09-28'
AND [LATITUDE]  BETWEEN @FLT_LATITUDE-0.010 AND @FLT_LATITUDE+0.010
AND [LONGITUDE] BETWEEN @FLT_LONGITUDE-0.010 AND @FLT_LONGITUDE+0.010

方法2:计算每个坐标的距离(圆),平均执行5500ms

DECLARE @GGP_LOCATE_POINT GEOGRAPHY = GEOGRAPHY::Point( 22.26663,113.821256666667, 4326);  
SELECT *  FROM [dbo].[ALERT]
WHERE [ALERT_TIME] BETWEEN '2015-09-08' AND  '2015-09-28'
AND  @GGP_LOCATE_POINT.STDistance(GEOGRAPHY::Point([LATITUDE],[LONGITUDE], 4326))<=1000

方法3:计算目标是否在范围内,平均执行7500ms

DECLARE @GGP_LOCATE_POINT GEOGRAPHY = GEOGRAPHY::Point( 22.26663,113.821256666667, 4326);  
DECLARE @buffer GEOGRAPHY;
set @buffer=@GGP_LOCATE_POINT.STBuffer(1000);
SELECT *  FROM [dbo].[ALERT]
WHERE [ALERT_TIME] BETWEEN '2015-09-08' AND  '2015-09-28'
AND @buffer.Filter(GEOGRAPHY::Point([LATITUDE],[LONGITUDE], 4326))>1000

补充:计算指定范围对应的经纬度大小

//地球子午线(南极到北极的连线)长度39940.67公里,纬度一度合110.94公里,一分合1.849公里,一秒合30.8米,不同纬度的间距是一样的。
//地球赤道圈长度40075.36公里,深圳在北纬22度左右,纬度圈长为111.32*cos(a),
//因此这里的经度一度合103.566436555110152670083196192

/// 
/// 获取指定距离的经度
/// 
/// 对应的纬度
/// 
/// 
public double GetLongitude(double org, float range)
{
    // 1 经度的距离为 111.32*cos(a)
    const double n = 1113200f;
    double angle = Math.PI * org / 180.0;
    return range / (n * Math.Cos(angle));
}

/// 
/// 获取指定距离的纬度
/// 
/// 
/// 
/// 
public double GetLatitude( float range)
{
    // 1 纬度的距离为 110.94公里
    const double n = 1109400f;
    return range / n;
}

你可能感兴趣的:(C#,SQL,地理信息)