16
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MySQLで2点間の距離を求める関数を自作する(ストアドファンクション)

Last updated at Posted at 2014-03-13

distance_sphere(自作 MySQL 距離計算関数)

MySQL5.6でこれが実装されたのかされていなのかについてはよくわかりませんが、2点間の距離をもとめるためだけに、OPEN GISとか、何かモジュールを入れたりするのも面倒(いや、実際にはその手順をよくわかっていない)なのでストアドファンクションで作ってみました。

distance_sphereとは

PostgreSQLでは、そこそこ有名な。POST GIS そのPOST GISに含まれる点間距離関数です。私も、一歩でも近づきたいという気持ちから、distance_sphereという同じ名前でストアドファンクションにしてみましたが、よくよく考えて考えてみると、紛らわしい・・。

単純には、経度・緯度から直線の距離をメートルで返しますよという関数なのですが、地球は丸い!ということを考慮してw
ヒュベニの距離計算式というものをベースに作ってみたものが、以下のそれです。まぁ、内容について、あれはこうだのどうだのヒュベニさんって誰なのとか聞かれてもさっぱりわからないのでご了承願います。

ちなみに公式は、以下のサイトに載ってました

また、以下がストアドファンクションのソースになります。MySQLのコンソールにコピペしてくれればきっと入ります。

  • distance_sphere
DROP FUNCTION IF EXISTS distance_sphere ;

DELIMITER //
CREATE FUNCTION distance_sphere(
  lat1 decimal(30,10), 
  lng1  decimal(30,10), 
  lat2  decimal(30,10), 
  lng2  decimal(30,10)
) 
RETURNS decimal(30,10) DETERMINISTIC

BEGIN
  DECLARE p decimal(30,10);
  DECLARE m decimal(30,10);
  DECLARE n decimal(30,10);
  DECLARE a decimal(30,10);
  DECLARE meter decimal(30,10);
  DECLARE wlat1 decimal(30,10);
  DECLARE wlng1 decimal(30,10);
  DECLARE wlat2 decimal(30,10);
  DECLARE wlng2 decimal(30,10);

  DECLARE latidiff decimal(30,10);
  DECLARE longdiff decimal(30,10);

  DECLARE wx decimal(30,10);
  DECLARE wy decimal(30,10);

  SET wlat1 = lat1 * (PI()/180);
  SET wlng1 = lng1 * (PI()/180);

  SET wlat2 = lat2 * (PI()/180);
  SET wlng2 = lng2 * (PI()/180);

  SET p = ((wlat2 + wlat1) / 2);
  SET latidiff = wlat2 - wlat1;
  SET longdiff = wlng2 - wlng1;

-- M:子午線曲率半径
  SET m = 6335439 / SQRT(POWER(1 - 0.006694 * sin(p) * sin(p), 3));

-- N:卯酉線曲率半径
  SET n = 6378137 / SQRT(1 - 0.006694 * sin(p) * sin(p));

-- 2点間の距離(m)
  SET wx = m * latidiff;
  SET wy = n * cos(p) * longdiff;

  SET meter = SQRT(wx * wx + wy * wy);

  RETURN meter;

END;
//
DELIMITER ;

さっそく使ってみよう!!

実際、プログラムに書けばいいじゃんとか言われたらおっしゃる通りなのですが、僕的には、SQLの中でこれを混ぜたいと思っていたので、そういう使い方を見せたいと思います。

以下2つのSQLサンプルを書きます

  • 品川駅(高輪口)から御殿山トラストシティまでの直線距離を求める
select distance_sphere(35.628770,139.737295,35.621438,139.736902) ;
+------------------------------------------------------------+
| distance_sphere(35.628770,139.737295,35.621438,139.736902) |
+------------------------------------------------------------+
|                                             814.2787425846 |
+------------------------------------------------------------+

814メートルでした。

  • では、品川駅(高輪口)を起点として半径500メートル以内にある、レストランを近いもの順に表示
seletct
  shop_name,
  distance_sphere(35.628770,139.737295,lat,lng) as distance
from
  shops
where
  distance_sphere(35.628770,139.737295,lat,lng) <= 500 AND
  category = 'レストラン'
order by
  distance_sphere(35.628770,139.737295,lat,lng) ;

すんませんテストデータ作っていないので、結果はなしでw

まとめ

このストアドファンクションを利用すればいろいろな場面で活躍できるようになると思います。たとえば彼女とのデートの際、行くお店に迷った時、さっとこんなSQLで近いお店をリストアップなんてしてみれば、きっと惚れ直すこと必至です。

ちなみに、距離系のスマホアプリっていくつか出ているけど、メガヒットしたアプリってそんなにないね。。マネタイズが難しいのかな。

16
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?