使用Microsoft Access减少按距离对邮政编码进行排序的计算时间

时间:2019-01-04 21:02:04

标签: sql vba ms-access access-vba

我对使用Microsoft Access按与用户输入的邮政编码之间的距离对客户端(请参阅下表)进行排序有疑问。我正在使用大圆距离公式(请参见下面的代码)来计算邮政编码之间的距离。我有一张表格,其中包含美国当前的每个邮政编码以及其经度和纬度坐标(请参见下面的第二张表)。该函数获取每个客户端的邮政编码并从第一张和第二张表中获取纬度和经度并使用计算它们之间的距离。这是我正在运行的SQL查询,该查询调用 GreatCircleDistance 公式:

PARAMETERS [Zip Code] IEEEDouble;
SELECT Clinics.Clinic, [US Zip Codes].ZIP, 
      [US Zip Codes].LAT, [US Zip Codes].LNG, 
      GreatCircleDistance([Zip Code],[LAT],[LNG],True,True) AS Distance
FROM [US Zip Codes] INNER JOIN Clinics ON [US Zip Codes].ZIP = Clinics.[Clinic ZIP];

此查询使用的大圆距离公式如下所示:

Private Const C_RADIUS_EARTH_KM As Double = 6370.97327862
Private Const C_RADIUS_EARTH_MI As Double = 3958.73926185
Private Const C_PI As Double = 3.14159265358979

Function GreatCircleDistance(ZipCode As Double, _
        Latitude2 As Double, Longitude2 As Double, _
        ValuesAsDecimalDegrees As Boolean, _
        ResultAsMiles As Boolean) As Double

Dim lat1 As Double
Dim lat2 As Double
Dim long1 As Double
Dim long2 As Double
Dim X As Long
Dim Delta As Double

If ValuesAsDecimalDegrees = True Then
    X = 1
Else
    X = 24
End If

' convert to decimal degrees
'POTENTIAL PROBLEM
lat1 = DLookup("[US Zip Codes].LAT", "[US Zip Codes]", "[US Zip Codes].ZIP = '" & ZipCode & "'") * X
long1 = DLookup("[US Zip Codes].LNG", "[US Zip Codes]", "[US Zip Codes].ZIP = '" & ZipCode & "'") * X
'POTENTIAL PROBLEM

lat2 = Latitude2 * X
long2 = Longitude2 * X

' convert to radians: radians = (degrees/180) * PI
lat1 = (lat1 / 180) * C_PI
lat2 = (lat2 / 180) * C_PI
long1 = (long1 / 180) * C_PI
long2 = (long2 / 180) * C_PI

' get the central spherical angle
Delta = ((2 * ArcSin(Sqr((Sin((lat1 - lat2) / 2) ^ 2) + _
Cos(lat1) * Cos(lat2) * (Sin((long1 - long2) / 2) ^ 2)))))

If ResultAsMiles = True Then
    GreatCircleDistance = Delta * C_RADIUS_EARTH_MI
Else
    GreatCircleDistance = Delta * C_RADIUS_EARTH_KM
End If

End Function



Function ArcSin(X As Double) As Double
    ' VBA doesn't have an ArcSin function. Improvise.
    ArcSin = Atn(X / Sqr(-X * X + 1))
End Function

这是拥有我所有客户的第一张桌子。为了简单起见,我仅添加了三个,但文件上记录了大约2000条记录:

Clinic            City        State     Clinic ZIP
Clinic #1       Lakeland        FL         33809
Clinic #2        Smyrna         TN         37167
Clinic #3       Kissimmee       FL         34747
...

这是第二个具有每个美国邮政编码的表。记录的邮政编码超过41,000:

ID       ZIP         LAT           LNG
1       00501      40.8133      -73.0476      
2       00601       18.18       -66.7522
3       00602      18.3607      -67.1752
4       00603      18.4544       -67.122
...

现在,此方法有效,但是要花很长时间才能计算出输入的邮政编码与每个2000ish客户邮政编码之间的距离。我认为当我使用 DLookUp 函数获取用户输入的邮政编码的纬度和经度时,问题出在大圆距离公式中。有谁知道我该如何减少计算时间?谢谢

2 个答案:

答案 0 :(得分:2)

由于您需要比较两对不相关的坐标,因此请考虑一个交叉连接查询,该查询在MS Access中的FROM子句中使用逗号分隔的源。然后将两个 LAT LNG 对都传递到距离公式中。

但是,请确保包含WHERE子句以筛选作为参数传入的特定邮政编码(否则,您将同时运行这两个集合的笛卡尔积)。这应该返回一个单行结果集,以对内部联接的所有行重复:

PARAMETERS [ZipCodeParam] TEXT(255);
SELECT c.Clinic, us.ZIP, us.LAT, us.LNG, 
       p.ZIP, p.LAT, p.LNG,
       GreatCircleDistance(p.[LAT], p.[LNG], us.[LAT], us.[LNG], True, True) AS Distance
FROM [US Zip Codes] p, 
     ([US Zip Codes] us
      INNER JOIN Clinics c
          ON us.ZIP = c.[Clinic ZIP])
WHERE p.ZIP = ZipCodeParam;

当然可以调整函数参数并删除不需要的DLookUp调用:

Function GreatCircleDistance(Latitude1 As Double, Longitude1 As Double, _
        Latitude2 As Double, Longitude2 As Double, _
        ValuesAsDecimalDegrees As Boolean, _
        ResultAsMiles As Boolean) As Double

...

lat1 = Latitude1 * X
lng1 = Longitude1 * X

lat2 = Latitude2 * X
lng2 = Longitude2 * X

...

End Function

答案 1 :(得分:0)

Dlookup代码可能是问题所在。您的DLookup代码看起来不正确,并且无法在我的系统上运行。这段代码有效:

lat1 = DLookup(“ LAT”,“ [美国邮政编码]”,“ ZIP =”&邮政编码)* X

lat1 = DLookup(“ LNG”,“ [美国邮政编码]”,“ ZIP =”&邮政编码)* X

https://www.techonthenet.com/access/functions/domain/dlookup.php