SQL Query获取三个最近的位置

时间:2014-10-09 17:09:23

标签: sql sql-server sql-server-2000

这是我的疑问难题:   - 我有一张客户表,其中包含经度和纬度    邮政编码。   - 我有一张经度和供应商的供应商表    纬度为他们的邮政编码。   - 之间没有任何关系    表。   - 我有一个用户定义函数来计算距离    在两组经度和纬度之间。

我有以下查询可以显示(最多)给定客户50英里范围内最近的三个供应商(dbo.latlngdistance是用户定义的函数):

select top 3 dname1, dcity, dstate, dzip, dbo.latlngdistance(dlr.latitude, dlr.longitude, 
    (select lat from homeowner where ho_identifier = 16), 
    (select lng from homeowner where ho_identifier = 16)) AS SortDistance
from dlr
where dbo.latlngdistance(dlr.latitude, dlr.longitude, 
    (select lat from homeowner ho_identifier = 16), 
    (select lng from homeowner where ho_identifier = 16)) between 0 and 50
Order By SortDistance

我还有另一个查询,它返回所有客户50英里范围内的所有供应商(在此示例中我限制了客户数量,因为此查询的性能非常糟糕):

select ho.ho_identifier, ho.ho_firstname, ho.ho_lastname, ho.ho_email, dname1, dcity, dstate, dzip
from dlr
    cross join homeowner ho
where dbo.latlngdistance(dlr.latitude, dlr.longitude, 
    (select lat from homeowner ho2 where ho.ho_identifier = ho2.ho_identifier), 
    (select lng from homeowner ho3 where ho.ho_identifier = ho3.ho_identifier)) between 0 and 50
and ho.ho_identifier in (16, 17, 18, 19, 20)
Order By ho.ho_identifier

所以我的问题是我如何获得(最多)半径50英里范围内最靠近所有客户的三家供应商?

2 个答案:

答案 0 :(得分:0)

我会创建一个类似于此的定义的视图:

SELECT 
    ho.ho_identifier, dlr.dname1, --dlr.id would be even better, but you didnt give the name of the id column
    dbo.latlngdistance(dlr.latitute, dlr.longtitude, ho.lat, ho.lng) AS distance
FROM dlr d
CROSS JOIN homeowner ho

鉴于此视图将被称为calculatedDistances,您可以找到最近的支持者,例如:

SELECT ho.ho_identifier, dlr.dname1
FROM homeowner ho
JOIN calculatedDistances dis
    ON dis.ho_identifier = ho.ho_identifier
WHERE 
    NOT EXISTS(
        SELECT 1
        FROM calculatedDistances nearer
        WHERE
            nearer.distance < dis.distance
            AND nearer.ho_identifier = ho.ho_identifier
    )

找到最接近的三个会更棘手,可能会涉及一些严重的性能问题。你可以这样做:

SELECT 
    dis.ho_identifier, dis.dname1
FROM calculatedDistances dis
LEFT JOIN calculatedDistances nearer
    ON nearer.ho_identifier = dis.ho_identifier
    AND nearer.distance < dis.distance
GROUP BY dis.ho_identifier, dis.dname1
HAVING ISNULL(COUNT(1), 0) < 3

再次 - 如果遇到性能问题,您可能需要将calcutedDistance存储在其他表中。

如果我犯了任何错误,现在已经很晚了。如果是这样,请评论这个答案,我会尽力纠正自己。

答案 1 :(得分:0)

这是前同事建议的:

我想我会尝试将目标房主收集到一个临时表中以保存内容,然后使用SQL逐步逐步完成每一步。

比如(记住你我无法测试任何这个)

Select HO_Identifier, zip.lat, zip.lng INTO MyTempHO
From DBC_Homeowner
LEFT Join Zip on zip.zip = left(5,HO_Zip) AND Zip.ll = 'L'  //I think there might also be a function to get lat/lng from zip....
WHERE <Your homeowner selection criteria>

这应该会给你一个较小的表来使用。检查所有Lat,Lng字段是否已填写,某些部分的拉链可能存在问题。当然是左(5只适用于美国,不适用于加拿大)

创建另一个表来保存结果,例如

CREATE TABLE MyResults (HO_Identifier int,DLR_Identifier int)

写一个循环来遍历每一行并找到前3个经销商,例如

//将所有这些作为一个语句运行

Declare @HO_Identifier int, @HO_Lat double, @HO_Lng double

Declare Cursor HO from select HO_Identifier , Lat, Lang from MyTempHO

OPEN HO
FETCH FROM HO Into @HO_Identifier, @HO_Lat, @HO_Lng 
While @@INDEX = 0
BEGIN
    Insert MyResults (@HO_Identifier, Dlr.dlr_Identifier) Select TOP 3 DLR_Identifier from dlr 
        where dbo.LAtLngDistance(@HO_Lat, @HO_Lng, dlr.lat, dlr.lng) < 100
        AND <Your other dlr criteria>
        AND dlr.lng between HO_Lng + <some negative amount to limit results> AND HO_Lng - <Same negative amount> //Note lng is negative!
        ORDER BY dbo.LAtLngDistance(@HO_Lat, @HO_Lng, dlr.lat, dlr.lng)

    FETCH NEXT FROM HO Into @HO_Identifier, @HO_Lat, @HO_Lng 
END

CLOSE HO
DEALLOCATE HO