用于在NE / SW范围内提取位置的SQL

时间:2014-07-23 10:39:05

标签: mysql sql geolocation

我正在尝试使用SQL查询来动态地提取位于城市范围内的事件。我有一个城镇/城市列表,使用Google Geocoding我可以获得每个城市的东北和西南边界。

我看过代码解释了如何检查一个位置(通过lat和long)是否在美国这样的地方的范围内,但我读过这对整个世界都不起作用。

我已经尝试过以下公式,但它似乎不起作用:

AND ( 
    ($swLat < $neLat AND lat BETWEEN $swLat AND $neLat) 
        OR 
    ($neLat < $swLat AND lat BETWEEN $neLat AND $swLat)
    AND 
    ($swLng < $neLng AND lng BETWEEN $swLng AND $neLng) 
        OR 
    ($neLng < $swLng AND lng BETWEEN $neLng AND $swLng)
)

刚刚尝试了下面的第一个建议,这是我得到的输出:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 
FROM wp_posts 
INNER JOIN lat_lng_post ON wp_posts.ID = lat_lng_post.post_id 
WHERE 1=1 
AND wp_posts.ID IN (10027,10095,...,10657) 
AND wp_posts.post_type = 'event' 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') 
AND lat_lng_post.lat = lat 
AND lat_lng_post.lng = lng 
AND ( 
       ( 
           (52.385999 < 52.5688762) AND (lat BETWEEN 52.385999 AND 52.5688762) 
           OR 
           (52.5688762 < 52.385999) AND (lat BETWEEN 52.5688762 AND 52.385999) 
        ) AND (
           (-2.0174336 < -1.7098294) AND (lng BETWEEN -2.0174336 AND -1.7098294) 
           OR 
           (-1.7098294 < -2.0174336) AND (lng BETWEEN -1.7098294 AND -2.0174336) 
        ) 
    )
ORDER BY wp_posts.post_date DESC 
LIMIT 0, 10

编辑2 从barryhunter的回答中,我有一个在查询中调用的函数:

function bounds_query($bounds) {

    $swLat = $_SESSION['search']['SW'][0];
    $swLng = $_SESSION['search']['SW'][1];
    $neLat = $_SESSION['search']['NE'][0];
    $neLng = $_SESSION['search']['NE'][1];

    $bounds .= ' AND (lat BETWEEN '.$swLat.' AND '.$neLat.')';
    if ($neLng < $swLng) {
      $bounds .= ' AND NOT (lng BETWEEN '.$neLng.' AND '.$swLng.')';
    } else {
      $bounds .= ' AND (lng BETWEEN '.$swLng.' AND '.$neLng.')';
    }

    return $bounds;
}

这将输出以下SQL:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 
FROM wp_posts 
INNER JOIN lat_lng_post 
ON wp_posts.ID = lat_lng_post.post_id 
WHERE 1=1 
AND wp_posts.ID IN (10060,10293,...,10657) 
AND wp_posts.post_type = 'event' 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') 
AND lat_lng_post.lat = lat 
AND lat_lng_post.lng = lng 
AND (lat BETWEEN 52.385999 AND 52.5688762) AND (lng BETWEEN -2.0174336 AND -1.7098294)      
ORDER BY wp_posts.post_date DESC 
LIMIT 0, 10

2 个答案:

答案 0 :(得分:1)

问题是当你的BBOX跨越日期时,我在这里注意到:http://sphinxsearch.com/forum/view.html?id=8969与狮身人面像相关,但同样适用于mysql ....

$where = "(lat BETWEEN $swLat AND $neLat)";
if ($neLng < $swLng) {
  $where .= " AND NOT (lng BETWEEN $neLng AND $swLng)";
} else {
  $where .= " AND (lng BETWEEN $swLng AND $neLng)";
}

使用否定过滤器来排除东西方之间的项目(因为东方longtitde值现在位于globe0的西侧 - 只留下跨越日期线的狭窄停靠点上的结果。

弗兰基虽然你不应该多谈这个问题,因为不应该跨越日期线的任何城市!

(会认为这段代码更干净,因为它避免了对纬度的冗余检查,并将其移动到PHP而不是mysel,但您也可以通过向(lng BETWEEN $neLng AND $swLng)子句添加NOT逻辑来修复代码)

答案 1 :(得分:0)

在看得太深之前,看起来你错过了OR的一些括号

AND (
        (
            ($swLat < $neLat AND lat BETWEEN $swLat AND $neLat) 
            OR 
            ($neLat < $swLat AND lat BETWEEN $neLat AND $swLat)
        )
        AND 
        (
            ($swLng < $neLng AND lng BETWEEN $swLng AND $neLng) 
            OR 
            ($neLng < $swLng AND lng BETWEEN $neLng AND $swLng)
        )
)