5

各郵便番号のlat/lngを含む郵便番号MySQLデータベースがあります。各州の中央の郵便番号を見つけるにはどうすればよいですか?私はこれを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がありますが、これも1回限りの操作であるため、結果をキャッシュしてもそれほど問題にはなりません。

  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が要求されていることがわかりました。各状態のおおよその中心緯度/経度のリストを取得したら、ループしてそれぞれに最も近い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 に答える