MySQL 空間情報型

準備

$ sudo docker run --platform linux/x86_64 -p 3307:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:latest
$ mysql -uroot -pmy-secret-pw -h127.0.0.1 -P3307
mysql > create database geosample;

空間情報の型

空間情報を表現する型は次のとおりです。

型名 意味
POINT
LINESTRING
POLYGON
GEOMETORY 上記すべてを表現できる
MULTIPOINT 点の集合
MULTILINESTRING 線の集合
MULTIPOLYGON 面の集合
GEOMETORYCOLLECTION 上記すべてを表現できる

空間情報の表し方

空間情報型を扱うサンプルです。
空間情報型はバイナリで管理されているため、SELECTしても分かりません。

mysql> create table geo (id INTEGER, pos GEOMETRY);
Query OK, 0 rows affected (0.02 sec)

-- 座標(3, 5)を挿入
mysql> insert into geo values (1, ST_GeomFromText('POINT(3 5)'));
Query OK, 1 row affected (0.01 sec)

-- (3, 5), (4, 7), (5, 2)を結んだ線を表現する値 LINESTRING(3 5, 4 7, 5 2)を挿入
mysql> insert into geo values (2, ST_GeomFromText('LINESTRING(3 5, 4 7, 5 2)'));
Query OK, 1 row affected (0.01 sec)

-- POLYGONは点を結んでいき最後に始点に戻る面を表す
-- (1, 1), (5, 1), (5, 5), (1, 5), (1, 1)を結んだときにできる面 POLYGON((1 1, 5 1, 5 5, 1 5, 1 1) を挿入
mysql> INSERT INTO geo VALUES (3, ST_GeomFromText('POLYGON((1 1, 5 1, 5 5, 1 5, 1 1))'));
Query OK, 1 row affected (0.01 sec)

-- selectで直接見るとバイナリで保存されていることがわかる
-- 先述のPOINT(3 5)がWKT(Well Known Text)に対してMySQLの内部表現にST_GeomFromText()に変換される.
mysql> select * from geo;
+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id   | pos                                                                                                                                                                                                  |
+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|    1 | 0x00000000010100000000000000000008400000000000001440                                                                                                                                                 |
|    2 | 0x000000000102000000030000000000000000000840000000000000144000000000000010400000000000001C4000000000000014400000000000000040                                                                         |
|    3 | 0x0000000001030000000100000005000000000000000000F03F000000000000F03F0000000000001440000000000000F03F00000000000014400000000000001440000000000000F03F0000000000001440000000000000F03F000000000000F03F |
+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)

MySQL内部表現からWKTへの変換はST_AsText()で計算できます。

-- pos はGEOMETRY型なのでPOINT, LINESTRINGなどの型が共存できる
mysql> SELECT id, ST_AsText(pos) FROM geo;
+------+--------------------------------+
| id   | ST_AsText(pos)                 |
+------+--------------------------------+
|    1 | POINT(3 5)                     |
|    2 | LINESTRING(3 5,4 7,5 2)        |
|    3 | POLYGON((1 1,5 1,5 5,1 5,1 1)) |
+------+--------------------------------+
3 rows in set (0.00 sec)

空間情報に対しての関数

POINT間の距離を計算したい場合ST_Distance()関数を用います。
ST_Distance()関数への引数にはMySQLの内部表現バイナリを入れることに注意。

mysql> SELECT ST_Distance(ST_GeomFromText('POINT(1 1)'), ST_GeomFromText('POINT(3 2)')) AS dist;
+------------------+
| dist             |
+------------------+
| 2.23606797749979 |
+------------------+
1 row in set (0.01 sec)

地球上の位置情報

上述の計算は平面での話です。
空間情報型の応用先は現実(地球上)の座標間の計算です。
測地系

-- CREATE  TABLE geo2 (id INTEGER, カラム GEOMETRY型 SRID 測地系のID);
mysql> CREATE TABLE geo2 (id INTEGER, pos GEOMETRY SRID 6668);
Query OK, 0 rows affected (0.02 sec)

-- 測地系6668で'POINT(43.06416667 141.3469444)'のPOINTを挿入
mysql> INSERT INTO geo2 VALUES (1, ST_GeomFromText('POINT(43.06416667 141.3469444)', 6668));
Query OK, 1 row affected (0.01 sec)