これは、haversine式を使用して地球上の2つの緯度と経度の距離を計算することについての質問です。「最も近いものを見つける」必要があるプロジェクトで使用します。このMySQLのストアド関数は、クエリで計算を行うのとは異なる結果をもたらすのはなぜですか?
haversineの式は、this postのMySQLでよく議論され、解決されています。
次に、this questionに保存された関数に変換するように頼んで、将来のプロジェクトで参照できるようにしました。長い形式の式を覚えたり、再入力する必要はありません。
そのすべてが良好です。私の関数が(わずかに)結果が異なるのは、式に直接入力することだけです。どうしてこれなの?
DELIMITER $$
DROP FUNCTION IF EXISTS haversine $$
CREATE FUNCTION `haversine`
(fromLatitude FLOAT,
fromLongitude FLOAT,
toLatitude FLOAT,
toLongitude FLOAT,
unit VARCHAR(20)
)
RETURNS FLOAT
DETERMINISTIC
COMMENT 'Returns the distance on the Earth between two known points of longitude and latitude'
BEGIN
DECLARE radius FLOAT;
DECLARE distance FLOAT;
IF unit = 'MILES' THEN SET radius = '3959';
ELSEIF (unit = 'NAUTICAL_MILES' OR unit='NM') THEN SET radius = '3440.27694';
ELSEIF (unit = 'YARDS' OR unit='YD') THEN SET radius = '6967840';
ELSEIF (unit = 'FEET' OR unit='FT') THEN SET radius = '20903520';
ELSEIF (unit = 'KILOMETRES' OR unit='KILOMETERS' OR unit='KM') THEN SET radius = '6371.3929';
ELSEIF (unit = 'METRES' OR UNIT='METERS' OR unit='M') THEN SET radius = '6371392.9';
ELSE SET radius = '3959'; /* default to miles */
END IF;
SET distance = (radius * ACOS(COS(RADIANS(fromLatitude)) * COS(RADIANS(toLatitude)) * COS(RADIANS(toLongitude) - RADIANS(fromLongitude)) + SIN(RADIANS(fromLatitude)) * SIN(RADIANS(toLatitude))));
RETURN distance;
END$$
DELIMITER ;
はここだけで、たとえば、ロンドンアイ、バッキンガム宮殿の間の距離を見つけるために、設定されたテストクエリのセットです:
は、だからここに私が書いた機能です。明らかに通常は、あなたが比較したい地理的に位置する「物」のデータベースのフィールドで目的地を置き換えます。例では
SET @milesModifier = 3959;
SET @myLat = 51.503228;
SET @myLong = -0.119703;
SET @destLat = 51.501267;
SET @destLong = -0.142697;
SELECT @kilometerModifier AS radius,
@myLat AS myLat,
@myLong AS myLong,
@destLat AS destLat,
@destLong AS destLong,
(@milesModifier * ACOS(COS(RADIANS(@myLat)) * COS(RADIANS(@destLat)) * COS(RADIANS(@destLong) - RADIANS(@myLong)) + SIN(RADIANS(@myLat)) * SIN(RADIANS(@destLat)))) AS longFormat,
haversine(@myLat,@myLong,@destLat,@destLong,'MILES') AS distanceMiles,
haversine(@myLat,@myLong,@destLat,@destLong,'NAUTICAL_MILES') AS distanceNautical,
haversine(@myLat,@myLong,@destLat,@destLong,'KM') AS distanceKm,
haversine(@myLat,@myLong,@destLat,@destLong,'METRES') AS distanceMetres,
haversine(@myLat,@myLong,@destLat,@destLong,'YARDS') AS distanceYards,
haversine(@myLat,@myLong,@destLat,@destLong,'FEET') AS distanceFeet,
haversine(@myLat,@myLong,@destLat,@destLong,'') AS distanceDefault
、我々はマイルを使用している - 私たちは、正確に3959までの半径(テスト中
@milesModifier、関数内
半径)を設定しました。
私が戻った(MySQLの5.2.6コミュニティ版に)面白かった結果、ハイライト:
| longFormat | distanceMiles |
|------------------|-----------------|
| 0.99826000106148 | 0.9982578754425 |
longFormatは、関数の結果クエリで行わ数学、distanceMilesされています。
結果が異なっている... OK、限りのプロジェクトで関数を使用するなど、取るに足りないそのので、しかし、私は、関数の内部または外部同じ数式が異なる結果を持っているか知って興味があります。
私は、FLOATの長さと関係があると推測しています - 機能には指定されていません。すべての数字のための十分なスペースを与えるために(30,15まで)指定しました。私が期待している出力がありますが、結果は若干異なります。
FLOATデータ型はおおよそのものです。代わりにDECIMALデータ型で試しましたか? http://dev.mysql.com/doc/refman/5.1/en/numeric-types.html – Mike
毎日何か新しいことを学ぶ...近似の利点は何ですか?計算が速くなりますか? – Codecraft
これは[データストレージ要件](http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html)と関連しています。 「浮動小数点値の問題」(http://dev.mysql.com/doc/refman/5.1/en/problems-with-float.html)も参照してください。私はちょうど 'DECIMAL(30,15)'でそれを試して、両方の計算から同じ結果を得ました。あなたはあなたの正確な要求に合うようにそれを調整することができるかもしれません。 – Mike