如何使用SQL连接选择使用lat / lng radius

时间:2012-10-18 22:11:43

标签: sql sql-server join gis latitude-longitude

我有SQL function使用他们的lat / lng坐标计算两点之间的距离。使用此功能,我可以根据给定点的距离从大型集合( GEOCODES表)中列出一组位置,如下所示:

DECLARE @LAT1 float, @LNG1 float,
SET @LAT1 = '34.169540'
SET @LNG1 = '-92.590990'

SELECT E.* FROM GEOCODES E
WHERE dbo.fnGetDistance(E.lat, E.lng, @LAT1, @LNG1, 'miles') < '20'

我有第二张表格( GEOMILES ),表格中各点之间的距离为:

LOCATION1  | STATE1  |  LOCATION2  |  STATE2  | DISTANCE
-----------+---------+-------------+----------+---------
New York   |   NY    |    Boston   |   MA     |   220

我想要实现的是SELECT查询,如果出发点在纽约20英里范围内,并且到达点在波士顿20英里范围内,则返回220的距离。到目前为止,我有这个,但是当我通过手动检查lat / lng点等加起来时它没有返回任何内容。非常感谢任何帮助!

DECLARE @FROM_LOC VARCHAR(100), @FROM_STA VARCHAR(2), @TO_LOC VARCHAR(100), @TO_STA VARCHAR(2)

SET @FROM_LOC = 'NEWARK'
SET @FROM_STA = 'NJ'

SET @TO_LOC = 'MEDFORD'
SET @TO_STA = 'MA'      

SELECT G.DIST FROM GEOMILES G, GEOCODES E
JOIN GEOCODES C ON C.asciiname = @FROM_LOC AND C.admin1 = @FROM_STA
JOIN GEOCODES D ON D.asciiname = @TO_LOC AND D.admin1 = @TO_STA
WHERE dbo.fnGetDistance(E.lat, E.lng, C.lat, C.lng, 'miles') < '20'
AND dbo.fnGetDistance(E.lat, E.lng, D.lat, D.lng, 'miles') < '20'

3 个答案:

答案 0 :(得分:1)

我认为这就是你所追求的(使用你的表结构)。 。

SELECT G.DIST
FROM GEOMILES G
, GEOCODES F --from airport
, GEOCODES E --to airport
, GEOCODES C --from location
, GEOCODES D --to location

WHERE C.asciiname = @FROM_LOC 
AND C.admin1 = @FROM_STA

AND D.asciiname = @TO_LOC 
AND D.admin1 = @TO_STA

AND dbo.fnGetDistance(F.lat, F.lng, C.lat, C.lng, 'miles') < 20
AND dbo.fnGetDistance(E.lat, E.lng, D.lat, D.lng, 'miles') < 20

and G.Location1 = F.asciiname
and G.Location2 = E.asciiname
and G.State1 = F.admin1
and G.State2 = E.admin1

备用版本(我认为这会更好)

SELECT G.DIST
FROM GEOMILES G
inner join
(
    select fromAirport.asciiname
    , fromAirport.admin1
    from GeoCodes fromAirport
    where exists
    (
        select top 1 1
        from GeoCodes fromLocation
        where fromLocation.asciiname = @FROM_LOC
        and fromLocation.admin1 = @FROM_STA
        and dbo.fnGetDistance(fromLocation.lat, fromLocation.lng, fromAirport.lat, fromAirport.lng, 'miles') < 20
    )
) fromA
    on G.Location1 = fromA.asciiname
    and G.State1 = fromA.admin1
inner join
(
    select toAirport.asciiname
    , toAirport.admin1
    from GeoCodes toAirport
    where exists
    (
        select top 1 1
        from GeoCodes toLocation
        where toLocation.asciiname = @TO_LOC
        and toLocation.admin1 = @TO_STA
        and dbo.fnGetDistance(toLocation.lat, toLocation.lng, toAirport.lat, toAirport.lng, 'miles') < 20
    )
) toA
    on G.Location1 = toA.asciiname
    and G.State1 = toA.admin1

答案 1 :(得分:0)

检查您的WHERE条款,您似乎正在寻找距离开始结束位置20英里内的所有代码 - 您已经指定距离相隔220英里。

此外,您将显式JOIN与隐式({逗号分隔FROM子句)混合在一起。请明确限定所有联接;除其他事项外,GE应该如何相互关联?

答案 2 :(得分:0)

这是我尝试解决方案 - 我已经在这里使用GEOGRAPHY来保存表格的脚本,但希望您可以根据自己的需要轻松调整 - 如果不是,请让我知道&amp;我会适应:

--setup
    declare @OneMileInMeters int = 1609

    declare @t table
    (
        id bigint not null identity(1,1) primary key clustered
        , name nvarchar(64)
        , lat float
        , long float
        , geo geography null
    )

    insert @t
          select 'Seattle', 47.455, -122.2310, null
    union select 'Boston',  42.372,  -71.0298, null
    union select 'Chicago', 41.953,  -87.6430, null
    union select 'Spokane', 47.668, -117.5290, null
    union select 'Philly',  39.888,  -75.2510, null
    union select 'NY',      40.7142, -74.0064, null
    union select 'Newark',  40.7356, -74.1728, null
    union select 'Medford', 42.4183, -71.1067, null

    update @t
    set geo = geography::Point(lat, long, 4326)

--query
    declare @fromLoc nvarchar(64) = 'Newark'
    , @toLoc nvarchar(64) = 'Medford'
    , @maxDistanceToAirport int = 20 * @OneMileInMeters


    select f2.name AirportFrom, t2.name AirportTo, f2.geo.STDistance(t2.geo) / @OneMileInMeters FlightDistance
    from @t f
    , @t t
    , @t f2
    , @t t2
    where f.name = @fromLoc
    and t.name = @toLoc
    and f.geo.STDistance(f2.geo) < @maxDistanceToAirport    
    and t.geo.STDistance(t2.geo) < @maxDistanceToAirport
    and t.id != t2.id
    and f.id != f2.id