2011-08-26 3 views
8

私はPHPでMySQLを使い始めました。カスタム関数を作成できるかどうかを知りたいと思います。このコードスニペットは私が何をしようとしているのかを説明する必要があります。カスタムMySQL関数を作成しますか?

// a somewhat complicated formula not suitable to embed into the query 
function Distance($latA, $lonA, $latB, $lonB) 
{ 
    // earth's radius 
    $radius = 3956; 

    $latA = deg2rad($latA); 
    $lonA = deg2rad($lonA); 
    $latB = deg2rad($latB); 
    $lonB = deg2rad($lonB); 

    // calculate deltas 
    $deltaLat = $latB - $latA; 
    $deltaLon = $lonB - $lonA; 

    // calculate Great Circle distance 
    $result = pow(sin($deltaLatitude/2.0), 2) + (cos($latA) * cos($latB) * pow(sin($deltaLon/2.0), 2)); 
    $distance = $radius * 2 * atan2(sqrt($result), sqrt(1 - $result)); 

    return $distance; 
} 

// how can I call Distance() in my query? 
$query = "SELECT lat, lon FROM zipcodes WHERE Distance(lat, lon, 0, 0) < 20"; 
mysql_query($query); 

ご協力いただきありがとうございます!

+1

だけFYI、あなたは完全にクエリから見つけることを行うことができます。実際には、緯度/経度に基づいて空間インデックスを使用した場合、結果は印象的です。信じられないほどの事実。 – Layke

+0

私はあなたが何を意味するか分からない、これを詳しく教えてもらえますか?また、「不適当」とは、パフォーマンスに関して(私はそれについては何も知らない)意味しませんでした。私はクエリがどれほど辛いほど長く続くかを意味しました。 –

答えて

12

このMySQL関数はアプリケーションで宣言し、データベースサーバーを再起動するまでデータベースに残ります。

mysql_query("CREATE FUNCTION Distance(LAT_A INT, LON_A INT, LAT_B INT, LON_B INT,) 
RETURNS INT 
READS SQL DATA 
DETERMINISTIC 
BEGIN 
DECLARE radius, deltaLat, deltaLon, result, distance BIGINT; 
SET radius=3956; 
SET deltaLat=LAT_B-LAT_A; 
SET deltaLon=LON_B-LON_A; 
SET result=POW(SIN(deltaLat/2), 2) + (COS(LAT_A) * COS(LAT_B) * POW(SIN(deltaLon/2.0), 2)); 
SET distance=radius * 2 * ATAN2(SQRT(result), SQRT(1 - result)); 
RETURN distance; 
END"); 

これは、MySQLのmathematical functionsを使用しています。この処理をデータベースにロードする作業は、迅速かつ効率的です(データはワイヤを渡って移動する必要はなく、必要な結果のみが返されます)。あなたがこれを宣言したら

、あなたはそうのようにそれを使用することができます:

$query = "SELECT lat, lon FROM zipcodes WHERE Distance(lat, lon, 0, 0) < 20"; 
mysql_query($query); 

データベースが再起動しない場合は、事前に宣言された関数や手続きは失われます。アプリケーションレベルでMySQLエラー1305(Function functionName does not exist)を正常に処理することは可能です。データベース・エラー・ハンドラで

switch (mysql_errno()): 
    case 1305: 
     if (false === $database->_declareStoredProcedureFlag) { 
      if ($c = preg_match_all("/FUNCTION [a-zA-Z0-9]+\." . 
       "([a-zA-Z0-9_]*) does not exist/is", 
       mysql_error(), $matches) 
      ) { 
       $storedFunctionName = $matches[1][0]; 
       $database->_declareStoredProcedureFlag = true; 
       if (true === $database->declareStoredFunction($storedFunctionName)) { 
        $result = mysql_query($query); 
       } 
      } 
     } 
     break; 
    ... 
+0

これは唯一のオプションですか?むしろ、現時点ではPHPに限定しておきたいと思います。私は答えを記すために数分待つでしょう。 –

+0

私はそれが起こっていないと思う。私はこれと一緒に行くつもりです、+1。歓声メイト。 –

+1

クエリで 'Distance()'関数呼び出しに 'lat'と' lon'という値を使用しているので、これらはデータベースから来ているので、唯一のオプションはそれらの値を含むデータセット全体を選択することですテーブルをPHPに変換し、それをPHPバージョンの関数で実行し、本質的にPHP(これはかなり遅い)でナンバー・クランチ(効率的に動作するように設計されたデータベース)を実行します。データベースからPHPにデータを転送するオーバーヘッドが増えます。これは最適な解決策ですが、明らかに複雑さが増します。 – Andy

1

あなたは確かにこれを行うMySQL関数を書くことができます。私は今1を書く時間がありますが、ここであなたが始めるところだしないでください。

http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html

+0

私はあなたのPHP関数を受け取り、MySQL関数にしたいと思っていました。ごめんなさい! –

+0

"。function_ame()"を使って関数を呼び出す方法を示した別の答えがありました。 PHPで関数を保持したい場合にも有効な構文です。 –

0

機能は引用符では動作しない」または「あなたは完全な停止でそれを分割する必要があるので( 。)

$query = mysql_query("SELECT lat, lon FROM zipcodes WHERE ".Distance($lat, $lon, 0, 0)." < 20"); 

・ホープ、このことができます:) MySQLがために、いくつかの機能が異なる場合がありますルーチンhttp://dev.mysql.com/doc/refman/5.0/en/stored-routines.html

を記憶している

+0

@thedaianは上で述べたように、 'lat'と' lon'はSELECT文の変数であるため、これは機能しません。 –

1

をたとえば、phpのdeg2radに相当するmysqlはmysqlのradians()関数です。私はあなたが同等の機能を作成できるはずだと思います。この方法では、これらのクエリは毎回ZIPコードテーブルをテーブルスキャンする必要があることに注意してください。

関連する問題