如何确定每个州的中心邮政编码?

时间:2012-10-23 16:41:48

标签: php mysql

我有一个邮政编码MySQL数据库,其中包含每个邮政编码的纬度/经度。如何查找每个州的中心邮政编码?我会在PHP中这样做。

2 个答案:

答案 0 :(得分: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. 人口稠密地区有很多邮政编码,人口稀少的地区很少。因此,确定的“质心”可能距离地理中心有一段距离(但如果符合要求,它可能是人口中心的合理代理)。

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

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

答案 1 :(得分: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