0

我正在尝试完成此Google 教程的修改

我编写了这个 SQL 来使用位置“名称”查询位置表。给定位置的名称,查询返回附近的比萨餐​​厅。为了做到这一点,我交叉加入了我的餐厅位置表,标题为“标记”,并使用 Haversine 公式计算距离。

    SELECT m.address,
       m.name,
       m.lat,
       m.lng,
       (3959 * ACOS(COS(RADIANS(poi.lat)) * 
       COS(RADIANS(m.lat)) * 
       COS(RADIANS(m.lng) - RADIANS(poi.lng)) + SIN(RADIANS(poi.lat))*
       SIN(RADIANS(m.lat)))) AS distance
    FROM markers poi
       CROSS JOIN markers m
    WHERE poi.address LIKE "%myrtle beach%"
          AND poi.id <> m.id HAVING distance < 200
   ORDER BY distance LIMIT 0,20

查询返回预期结果,但如果兴趣点在指定区域之外,在本例中为“默特尔海滩”,我每次匹配都会得到重复记录。这是因为 CROSS JOIN 很容易通过 DISTINCT 选择来修复。但是“lng”和“lat”字段是 FLOAT 类型,因此距离计算永远不会相同,即使对于重复记录也是如此。

这是回报的一个子集:

3901 North Kings Highway Suite 1, 默特尔比奇, SC | 芝加哥比萨公司以东| 33.716099 -78.855583 | 4.0285562196955125

1706 S Kings Hwy # A, 默特尔比奇, SC | 达美乐披萨:默特尔比奇 | 33.674881 | -78.905144 | 4.0285562196955125

82 Wentworth St, 查尔斯顿, SC | 安多利尼斯披萨 | 2.782330 | -79.934235 | 85.68177495224947

82 Wentworth St, 查尔斯顿, SC | 安多利尼斯披萨 | 32.782330 | -79.934235 | 89.71000040441085

114 Jungle Rd, 埃迪斯托岛, SC | Edisto Beach Inc 的雄鹿披萨 | 32.503971 -80.297951 | 114.22243529200529

114 Jungle Rd, 埃迪斯托岛, SC | Edisto Beach Inc 的雄鹿披萨 | 32.503971 -80.297951 | 118.2509427998286"

关于从这里去哪里有什么建议吗?

4

3 回答 3

1

您会得到重复的结果,因为这两点都匹配“默特尔海滩”。使用类似的条件poi.id < m.id来确保您只获得一个匹配项。

例子:

poi id    m id    distance
1         2       100
2         1       100

询问:

SELECT 
    m.address,
    m.name,
    m.lat,
    m.lng,
    (3959 * ACOS(COS(RADIANS(poi.lat)) * 
    COS(RADIANS(m.lat)) * 
    COS(RADIANS(m.lng) - RADIANS(poi.lng)) + SIN(RADIANS(poi.lat))*
    SIN(RADIANS(m.lat)))) AS distance
FROM markers poi
CROSS JOIN markers m
WHERE 
    (poi.address LIKE "%myrtle beach%" OR m.address LIKE "%myrtle beach%")
    AND poi.id < m.id 
HAVING distance < 200
ORDER BY distance LIMIT 0,20

或者,如果您确实在标记中有一个单行作为兴趣点,请指定该行而不是地址上的任何匹配项。那么你的条件poi.id <> m.id将确保没有重复。

SELECT 
    m.address,
    m.name,
    m.lat,
    m.lng,
    (3959 * ACOS(COS(RADIANS(poi.lat)) * 
    COS(RADIANS(m.lat)) * 
    COS(RADIANS(m.lng) - RADIANS(poi.lng)) + SIN(RADIANS(poi.lat))*
    SIN(RADIANS(m.lat)))) AS distance
FROM markers poi
CROSS JOIN markers m
WHERE 
    poi.id = (SELECT TOP(1) id FROM markers WHERE address LIKE "%myrtle beach%")
    AND poi.id <> m.id 
HAVING distance < 200
ORDER BY distance LIMIT 0,20
于 2014-02-22T21:19:04.287 回答
1

尝试:

select distinct x.address, x.name, y.lat, y.lng, x.distance
  from (SELECT m.address,
               m.name,
               m.lat,
               m.lng,
               (3959 *
               ACOS(COS(RADIANS(poi.lat)) * COS(RADIANS(m.lat)) *
                     COS(RADIANS(m.lng) - RADIANS(poi.lng)) +
                     SIN(RADIANS(poi.lat)) * SIN(RADIANS(m.lat)))) AS distance
          FROM markers poi
         cross JOIN markers m
         WHERE poi.address LIKE "%myrtle beach%"
           and poi.id <> m.id HAVING distance < 200) x
  join markers y
    on x.address = y.address
   and x.name = y.name
   and x.lat = y.lat
   and x.lng = y.lng
 order by x.distance limit 0, 20
于 2014-02-22T20:00:30.613 回答
0

回顾每个人的回答让我思考。我没有问为什么我得到重复的结果,而是开始想知道查询计算距离的两个默特尔比奇位置中的哪一个?答案是两者。这也解释了为什么我一开始每场比赛都能获得两项记录。

这是我的解决方案:

SELECT  m.address, m.name, m.lat, m.lng, (3959 
   * ACOS(COS(RADIANS(poi.lat)) * COS(RADIANS(m.lat)) 
   * COS(RADIANS(m.lng) - RADIANS(poi.lng)) + SIN(RADIANS(poi.lat))
   * SIN(RADIANS(m.lat))))     AS distance
FROM markers m
cross JOIN (
   select  name, lat, lng from markers
   where address like '%myrtle beach %'
   limit 1
) poi
HAVING distance < 200
ORDER BY name
LIMIT 0, 20

这并没有给我最准确的距离计算,因为它任意使用它找到的第一家餐厅作为震中。但就我的直接目的而言,这已经足够了。我认为要让这个应用程序准备好生产,我需要第二张包含城市中心坐标的城市表。

于 2014-02-23T00:07:11.880 回答