Создание пользовательской функции MySQL? - PullRequest
8 голосов
/ 26 августа 2011

Я только начал использовать MySQL с PHP, и я хотел бы знать, возможно ли создать пользовательскую функцию. Этот фрагмент кода должен иллюстрировать, что я пытаюсь сделать.

// 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);

Заранее спасибо за любую помощь!

Ответы [ 4 ]

12 голосов
/ 26 августа 2011

Вы объявляете эту функцию 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 .Выгрузка этой обработки в базу данных быстрая и эффективная (данные не должны перемещаться по проводам, и вы возвращаете только те результаты, которые хотите).

После того как вы заявили об этом, вы можетеиспользуйте его так:

$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;
    ...
1 голос
/ 26 августа 2011

Mysql хранит подпрограммы http://dev.mysql.com/doc/refman/5.0/en/stored-routines.html

Некоторые функции могут отличаться, например, mysql, эквивалентный php's deg2rad, является функцией mysql radians (). Я думаю, что вы должны быть в состоянии создать эквивалентную функцию. При таком подходе вы должны знать, что эти запросы должны будут каждый раз сканировать всю таблицу почтовых индексов.

1 голос
/ 26 августа 2011

Вы, конечно, можете написать функцию MySQL для этого.У меня нет времени, чтобы написать его сейчас, но вот с чего вы начали:

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

0 голосов
/ 26 августа 2011

Поскольку функции не работают в кавычках "или" вы должны разделить их с полной остановкой. (.)

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

Надеюсь, это поможет:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...