2014年2月5日水曜日

SQLServerで地図データ(緯度経度)を検索

先日FaceBookでDB上の地図座標を検索したいという話題がでていたので、SQLServerでやり方を調べてみました。
実現したいのは「現在地の座標から500m(任意の範囲)内の登録地点を検索する」となります。

SQLServer2008から空間データ用にgeometry型とgeography型がサポートされるようになりました。
geometry型は平面上の座標データ(一般的なxyグラフ)を扱います。
geography型は楕円体上の座標データを扱うので緯度経度データはこちらを利用することになると思います。

まずはサンプルテーブルを作成します。

CREATE TABLE T_TEST
(
 id int IDENTITY(1,1) NOT NULL,
 name nvarchar(50) ,
 address nvarchar(50) ,
 geo geography
)

次にサンプルデータを挿入します。今回は弊社近辺の銀行の所在地にしてみました。

INSERT INTO T_TEST(name,address,geo)
     VALUES('りそな銀行明石支店',
'明石市本町1丁目2-26',
geography::STGeomFromText('POINT(134.991151 34.647505)',4326))
INSERT INTO T_TEST(name,address,geo)
     VALUES('みずほ銀行明石支店',
'明石市大明石町1丁目5-1',
geography::STGeomFromText('POINT(134.993259 34.64798)',4326))
INSERT INTO T_TEST(name,address,geo)
     VALUES('三井住友銀行明石支店',
'明石市大明石町1丁目5-4',
geography::STGeomFromText('POINT(134.993299 34.647755)',4326))
INSERT INTO T_TEST(name,address,geo)
     VALUES('東京三菱UFJ銀行明石支店',
'明石市本町1丁目1-34',
geography::STGeomFromText('POINT(134.993251 34.647223)',4326))
INSERT INTO T_TEST(name,address,geo)
     VALUES('百十四銀行明石支店',
'明石市本町2丁目1-26',
geography::STGeomFromText('POINT(134.989622 34.647607)',4326))

geography型へのデータの挿入は「geography::STGeomFromText('POINT([経度] [緯度])',4326)」となります。(「経度」と「緯度」の間は半角スペースです。間違えるとエラーになります。)

------------------------------------------
追記
------------------------------------------
geography型へのデータの挿入は「geography::POINT([緯度],[経度],SRID)」でも可能です。
こちらのほうが直接的でわかりやすいかと思います。
------------------------------------------
追記終わり
------------------------------------------

SQLServerでのgeography型データは.NET 共通言語ランタイム (CLR) のデータ型として実装されているのでgeography::STGeomFromTextメソッドで座標を変換しています。「4326」はSRID (spatial reference ID) になります。(詳しく調べていないのですが固定値として指定しています。)


これで検索する準備ができました。

登録されているデータで任意の位置から特定範囲(この場合は円内)に含まれる地点を検索するには任意の位置座標とデータの位置座標の距離を求めることによって検索することができます。

距離(単位はメートルです)はgeography型のSTDistanceメソッドで求めることができます。

次のようにクエリを発行すると任意の座標から各データの位置データまでの距離が計算されます。

--任意の位置座標を代入する変数
declare @g geography

--任意の位置座標データとしてJR明石駅の位置座標を使用しています。
set @g=geography::STGeomFromText('POINT(134.993164 34.649096)',4326)

select name,address,@g.STDistance(geo) as distance from T_TEST

上記のクエリに以下の条件を加えると任意の範囲に含まれるデータを検索できます。

--200m以内にある地点を検索
where @g.STDistance(geo)<200

以上の内容をストアドもしくはユーザー定義関数としてSQLServerに登録して呼び出せるようにしておけば任意の位置データと検索したい範囲の距離を与えて検索することができるようになります。






0 件のコメント:

コメントを投稿