MySQL の Buffer という関数が位置範囲検索（中心から◯mとか）に便利そうだった

MySQL 5.6.1 からみたいだけど、[Buffer()](http://dev.mysql.com/doc/refman/5.6/en/spatial-operator-functions.html#function_buffer) という関数があるのを見つけたのでメモ。

> **Buffer( _g_ , _d_ )**
> Returns a geometry that represents all points whose distance from the geometry value _g_ is less than or equal to a distance of _d_.
> -- <cite>[_MySQL 5.6 Reference Manual :: 12.18.7 Spatial Operator Functions_](http://dev.mysql.com/doc/refman/5.6/en/spatial-operator-functions.html#function_buffer)</cite>

ジオメトリの値 _g_ から、範囲 _d_ の **円形の** ポリゴンを作成してくれる関数みたい。

## 実験例1

例えば以下のようなSQLを実行すると、

```sql
SELECT AsText(Buffer(POINT(139.663987,35.676577), 0.0005));
```

以下のようなポリゴンデータが返ってきた。

```text:結果
POLYGON((139.663987 35.676077,139.66396246616281 35.676077602271896,139.66393799142983 35.676079407636664,139.66391363476276 35.67608241174502,139.663889454839 35.6760866073598,139.66386550991004 35.67609198437341,139.66384185766137 35.67609852983214,139.6638185550733 35.67610622796741,139.66379565828382.......))
```

上記のポリゴンをGoogleマップで描画してみると、このようになった。  
<img src="https://qiita-image-store.s3.amazonaws.com/0/37122/26eb20a5-59f6-875c-d075-b409780f174c.png" style="max-width:100%">

第二引数 _d_ についてはよくわからない・・・
上記画像の横の直径は約90mだったので、とりあえず _0.0005 = 約100m_ と思っておくことにしたw

これまでこういうのは複雑な計算してやってたけど、一発でいけたのでちょっと嬉しかった。

## 実験例2

実験例1 の中心点は、渋谷区、中野区、杉並区が隣接するあたり。
試しにこの地点の「範囲100mぐらいに何区が含まれるか」というのをやってみる。

市区町村の境界データは [国土数値情報 行政区域データ](http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03.html) の東京都版を使用し、あらかじめ以下のようなテーブル構成で MySQL にブチ込んでおいた。

### cities テーブル

|city |name|polygon|
|:----|:--|:--|
|11385|千代田区|POLYGON((139.770135 35.705352,139.770131...|
|11385|中央区|POLYGON((139.788911 35.694704,139.787379...|
|11385|港区|POLYGON((139.77326 35.629484,139.773459...|
|11385|新宿区|POLYGON((139.722506 35.712266,139.722399...|
|...|...|...|

そして、とりあえず [Intersects()](http://dev.mysql.com/doc/refman/5.6/en/spatial-relation-functions-mbr.html#function_intersects) 関数で、範囲約100mぐらいに含まれる市区町村を検索してみる。

```sql
SELECT
`city`,
`name`
FROM `cities`
WHERE Intersects(`polygon`, Buffer(POINT(139.663987,35.676577), 0.0005));
```

```text:結果
+-------+-----------+
| city  | name      | 
+-------+-----------+
| 13114 | 中野区    |
| 13115 | 杉並区    |
| 13112 | 世田谷区  |
| 13113 | 渋谷区    |
+-------+-----------+
```

あら、なぜか世田谷区が登場したので MySQL 5.6 からまともになった [ST_Intersects()](http://dev.mysql.com/doc/refman/5.6/en/spatial-relation-functions-object-shapes.html#function_st-intersects) でやってみる。

```sql
SELECT
`city`,
`name`
FROM `cities`
WHERE ST_Intersects(`polygon`, Buffer(POINT(139.663987,35.676577), 0.0005));
```

```text:結果
+-------+-----------+
| city  | name      | 
+-------+-----------+
| 13114 | 中野区    |
| 13115 | 杉並区    |
| 13113 | 渋谷区    |
+-------+-----------+
```

今度はちゃんと返ってきた。

- - -

なんだか **ST_Buffer()** というのもあるっぽい（SQL文の Buffer() を ST_Buffer() にしても動く）けどソースを見つけられなかった。

それにしてもググラビリティの低い関数名がややこしいw

- - -

## 追記メモ(2014/07/23)

MySQL 5.6 から [ST_Distance()](http://dev.mysql.com/doc/refman/5.6/en/spatial-relation-functions-object-shapes.html#function_st-distance) という関数もあったので追記メモ。
その名の通り2点間の距離を測定する。

> **ST_Distance( _g1_ , _g2_ )**
> Returns the distance between _g1_ and _g2_.
> -- <cite>[_MySQL 5.6 Reference Manual :: 12.18.8.1 Spatial Relation Functions That Use Object Shapes_](http://dev.mysql.com/doc/refman/5.6/en/spatial-relation-functions-object-shapes.html#function_st-distance)</cite>

返り値は 100倍するとキロメートル、10万倍するとメートルになる。

```sql:東京タワーから東京スカイツリーまでの距離
SELECT ST_Distance(POINT(139.745437, 35.658644), POINT(139.810571, 35.710172))*100;
/* = 8.305162695576657 km */

SELECT ST_Distance(POINT(139.745437, 35.658644), POINT(139.810571, 35.710172))*100000;
/* = 8305.162695576657 m */
```