各郵便番号のlat/lngを含む郵便番号MySQLデータベースがあります。各州の中央の郵便番号を見つけるにはどうすればよいですか?私はこれをPHPで行います。
2 に答える
各郵便番号の座標を各州内で均等に重み付けされたポイントとして扱い、有効な「重心」に最も近い郵便番号を見つけたい場合は、次を組み合わせてMySQLで直接行うことができます。
PHP、MySQL、およびGoogleマップを使用したストアロケーターの作成に関するGoogleの記事の「 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
ノート
インデックス作成(列以外)はあまり役に立たないため、これはかなり遅くなる可能性
state
がありますが、これも1回限りの操作であるため、結果をキャッシュしてもそれほど問題にはなりません。人口密度の高い地域には多くの郵便番号があり、人口密度の低い地域には少数です。結果として、決定された「重心」は地理的中心からある程度離れている可能性があります(ただし、それが望ましい場合は、人口中心の妥当なプロキシになる可能性があります)。
各郵便番号に適切な重みを追加すると、妥当な概算が得られます。たとえば、地理的中心を見つけるために各郵便番号がカバーする総土地面積による重み。または、実際の人口中心を見つけるために、各郵便番号内に居住する人口によって。
真の地理的中心を持つ唯一の方法は、各州の境界から重心を導出することです。CloudMadeダウンロードサイトから適切な境界ポリゴンの座標をダウンロードできます。
それを恨みなさい。すべての状態を長方形にします。
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