5

我有一个邮政编码 MySQL 数据库,其中包含每个邮政编码的 lat/lng。如何找到每个州的中心邮政编码?我将在 PHP 中执行此操作。

4

2 回答 2

3

假设您希望将每个邮政编码的坐标视为每个州内的同等加权点,并找到最接近有效“质心”的邮政编码,您可以通过以下组合直接在 MySQL 中完成:

完整的查询是:

-- the closest ZIP code
SELECT state, z.zip_code
FROM   zip_codes z JOIN (

  -- the distance between the "centre of mass" and the closest ZIP code
  SELECT   state, c.lat, c.lon
           MIN(ACOS(
             COS(c.lat) * COS(RADIANS(z.lat)) * COS(RADIANS(z.lon) - c.lon)
           + SIN(c.lat) * SIN(RADIANS(z.lat))
           )) min
  FROM     zip_codes z JOIN (

    -- the "centre of mass" of each state
    SELECT   state, 
             ATAN2(
               SUM(SIN(RADIANS(lat))) / COUNT(*),
               SQRT(
                 POW(SUM(COS(RADIANS(lat)) * SIN(RADIANS(lon))) / COUNT(*), 2)
               + POW(SUM(COS(RADIANS(lat)) * COS(RADIANS(lon))) / COUNT(*), 2)
               )
             ) AS lat,
             ATAN2(
               SUM(COS(RADIANS(lat)) * SIN(RADIANS(lon))) / COUNT(*),
               SUM(COS(RADIANS(lat)) * COS(RADIANS(lon))) / COUNT(*)
             ) AS lon
    FROM     zip_codes
    GROUP BY state

  ) c USING (state)
  GROUP BY state

) d USING (state)
WHERE  ACOS(
         COS(d.lat) * COS(RADIANS(z.lat)) * COS(RADIANS(z.lon) - d.lon)
       + SIN(d.lat) * SIN(RADIANS(z.lat))
       ) = d.min

笔记

  1. 这可能会很慢,因为索引(除了在state列上)不会有太大用处,但又是一次性的操作,所以缓存结果不应该证明是一个太大的问题。

  2. 人口稠密地区的邮政编码较多,而人烟稀少的地区则很少。因此,确定的“质心”可能与地理中心有一段距离(但如果需要,它可能是人口中心的合理代表)。

    为每个邮政编码添加适当的权重将产生合理的近似值:例如,每个邮政编码覆盖的总土地面积的权重以找到地理中心;或按每个邮政编码内的人口居民来查找实际的人口中心。

    拥有一个真正的地理中心的唯一方法是从每个州的边界推导出质心。您可以从CloudMade 下载站点下载合适的边界多边形的坐标。

于 2012-10-23T17:32:58.700 回答
2

混搭它。使所有状态为矩形。

SELECT
  state,
  (MAX(lat)-MIN(lat))/2 + MIN(lat) 'center_lat',
  (MAX(lng)-MIN(lng))/2 + MIN(lng) 'center_lng'
FROM table
GROUP BY state

它并不完美,但除非你喜欢复杂的数学,否则它是最糟糕的情况。

编辑:我只是重新阅读了这个问题,意识到它不是要求中心纬度/经度,而是中心拉链。检索到每个州的大致中心 lat/lng 列表后,您可以循环并找到离每个州最近的 ZIP。

SELECT
  zip,
  ABS(lat-$center_lat) + ABS(lng-$center_lng) 'diff'
FROM table
WHERE state = $state
ORDER BY diff ASC
LIMIT 1
于 2012-10-23T16:51:38.547 回答