今回から2回に分けて、
数値型で保存する
緯度経度の情報をデータベースへ格納するときに、
緯度 | -90~90 |
経度 | -180~180 |
はてなフォトライフでは、
latitude decimal(7,4) longitude decimal(7,4)
decimal(7,4)という指定は、
あるオブジェクトの緯度経度を保存し、
Geometry型で保存する
続いて、
Geometry型とは、
例えば、
CREATE TABLE spot ( spot_id INT NOT NULL, latlon GEOMETRY NOT NULL, PRIMARY KEY (spot_id), SPATIAL KEY (latlon) ) Engine=InnoDB;
CREATE文の最後にEngine=MyISAMと指定されているのは、
SPATIAL INDEXは空間データのIndexで、
Geometry型へのデータの挿入
Geometry型のカラムにデータを挿入する場合、
INSERT INTO spot (spot_id , latlon ) VALUES (1, GeomFromText('POINT(137.10 35.20)'));
GeomFromTextは、
Geometry型のデータの取得
上記SQL文を実行してデータを作成したあと、
> select * from spot2; +---------+---------------------------+ | spot_id | latlon | +---------+---------------------------+ | 1 | 33333#a@??????A@ | +---------+---------------------------+ 1 row in set (0.00 sec)
latlon型のところが文字化して表示されました。Geometry型から、
select spot_id, X(latlon), Y(latlon), ASTEXT(latlon) from spot; +---------+-----------+-----------+-------------------+ | spot_id | X(latlon) | Y(latlon) | ASTEXT(latlon) | +---------+-----------+-----------+-------------------+ | 1 | 137.1 | 35.2 | POINT(137.1 35.2) | +---------+-----------+-----------+-------------------+ 1 row in set (0.00 sec)
X、
矩形エリアのスポットを取得する
それでは、
> select spot_id, ASTEXT(latlon) from spot where MBRContains(GeomFromText('LINESTRING(138.00 36.00, 135.00 35.00)'), latlon); +---------+-------------------+ | spot_id | ASTEXT(latlon) | +---------+-------------------+ | 1 | POINT(137.1 35.2) | +---------+-------------------+ 1 row in set (0.00 sec)
where句のところに、
- LINESTRING(138.
00 36. 00, 135. 00 35. 00) - これは、
「(35. 00 , 135. 00) と (36. 00 , 138. 00)の2点で表現される直線」 の文字列表現にになります。先程のPOINT(経度 緯度)同様、 矩形のエリアは、 LINESTRING(地点Aの経度 地点Aの緯度, 地点Bの経度 地点Bの緯度)という文字列で表現されます。 - GeomFromText(A)
- LINESTRINGの文字列表現を、
実際のGeometry型に変換しています。 - MBRContains(A B)
- この関数は、
Aの最小外接矩形に、 Bの最小外接矩形が含まれているかどうかを判定します。先のSQLではAの部分にLINESTRINGが、 Bの部分にはgeometry型のlatlonカラムの値が入るので、 Aで指定された直線が最小外接する矩形エリア内に入っているスポットで検索していることになります。

このように、
Geometry型にPOINT以外のデータを格納する
カンが良い方なら気づかれたかもしれませんが、
CREATE TABLE geo ( geo_id INT NOT NULL, name VARCHAR(255) NOT NULL, geo GEOMETRY NOT NULL, PRIMARY KEY (geo_id), SPATIAL KEY (geo) )ENGINE=MyISAM;
ここに、
INSERT INTO geo (geo_id , name, geo) values (1, 'はてな京都本社', geomFromText('POINT(135.761919 35.011141)')); INSERT INTO geo (geo_id , name , geo) values (2, '地下鉄烏丸御池', geomFromText('POINT(135.759666 35.010745)')); INSERT INTO geo (geo_id , name , geo) values (3, '東洞院通り上る', geomFromText('LINESTRING(135.761050 35.012165,135.761050 35.011040)')); INSERT INTO geo (geo_id , name , geo) values (4, 'ハートンホテル', polygonFromText('POLYGON((135.760497 35.012033,135.760497 35.011655, 135.760970 35.011655, 135.760970 35.012033,135.760497 35.012033))'));
これで4つのGeoデータが生成されました。1つ目と2つ目は、
それぞれ地図上に記述すると以下のようになります。

これらのGeoデータを対象に、
> select geo_id, name, ASTEXT(geo) from geo where MBRContains(GeomFromText('LineString(135.760009 35.011769, 135.762439 35.010851)'), geo); +--------+-----------------------+-----------------------------+ | geo_id | name | ASTEXT(geo) | +--------+-----------------------+-----------------------------+ | 1 | はてな京都本社 | POINT(135.761919 35.011141) | +--------+-----------------------+-----------------------------+ 1 row in set (0.01 sec)
結果は、

紫の部分に最小外接するものが対象になるため、
完全に含まれていなくても、
> select geo_id, name, ASTEXT(geo) from geo where MBRIntersects(GeomFromText('LineString(135.760009 35.011769, 135.762439 35.010851)'), geo); +--------+-----------------------+-------------------------------------------------------------------------------------------------------------------+ | geo_id | name | ASTEXT(geo) | +--------+-----------------------+-------------------------------------------------------------------------------------------------------------------+ | 1 | はてな京都本社 | POINT(135.761919 35.011141) | | 3 | 東洞院通り上る | LINESTRING(135.76105 35.012165,135.76105 35.01104) | | 4 | ハートンホテル | POLYGON((135.760497 35.012033,135.760497 35.011655,135.76097 35.011655,135.76097 35.012033,135.760497 35.012033)) | +--------+-----------------------+-------------------------------------------------------------------------------------------------------------------+ 3 rows in set (0.00 sec)
もちろん、

> select geo_id, ASTEXT(geo) from geo where MBRContains(GeomFromText('LineString(135.760009 35.012279, 135.762439 35.010851)'), geo); +--------+-------------------------------------------------------------------------------------------------------------------+ | geo_id | ASTEXT(geo) | +--------+-------------------------------------------------------------------------------------------------------------------+ | 1 | POINT(135.761919 35.011141) | | 3 | LINESTRING(135.76105 35.012165,135.76105 35.01104) | | 4 | POLYGON((135.760497 35.012033,135.760497 35.011655,135.76097 35.011655,135.76097 35.012033,135.760497 35.012033)) | +--------+-------------------------------------------------------------------------------------------------------------------+ 3 rows in set (0.00 sec)
本連載の第2回で、
Geometry型は、
> また、
次回予告
今回は、
次回は、