2011-08-26 15 views
8

Właśnie zacząłem używać MySQL z PHP i chciałbym wiedzieć, czy można utworzyć niestandardową funkcję. Ten fragment kodu powinien zilustrować, co próbuję zrobić.Tworzenie niestandardowej funkcji 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); 

Z góry dziękuję za pomoc!

+1

Wystarczy FYI, można to zrobić doskonale odnaleźć z zapytania. W rzeczywistości, jeśli użyjesz indeksu przestrzennego na podstawie twoich lat/lngs i przekonasz się, że wyniki są imponujące. Niesamowity. – Layke

+0

Nie jestem pewien co masz na myśli, czy mógłbyś to wyjaśnić? Również "nieodpowiedni" nie miałem na myśli pod względem wydajności (nic o tym nie wiem); Miałem na myśli, jak długo będzie to długie pytanie. –

Odpowiedz

12

Deklarujesz tę funkcję MySQL w swojej aplikacji i pozostanie ona w bazie danych do czasu ponownego uruchomienia serwera bazy danych.

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

Używa MySQL's mathematical functions. Przeładowanie tego przetwarzania do bazy danych jest szybkie i wydajne (dane nie muszą podróżować przez przewód, a wyniki są zwracane tylko wtedy, gdy chcesz).

Po ogłosił to, można go używać tak:

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

Jednak jeśli zostanie uruchomiony ponownie bazy danych, wszelkie funkcje lub procedury zadeklarowane wcześniej zostaną utracone. Możliwe jest obsługiwanie błędu MySQL 1305 (Function functionName does not exist) z gracją na poziomie aplikacji.

W swojej obsługi błędów bazy danych:

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

Czy to jedyna opcja? Wolałbym, aby w tej chwili był ograniczony do PHP. Poczekam jeszcze kilka minut, aby zaznaczyć odpowiedź. –

+0

yeh Myślę, że to się nie dzieje. Idę z tym, +1. Zdrowie przyjacielu. –

+1

Ponieważ używasz wartości 'lat' i' lon' w wywołaniu funkcji 'Odległość()' w zapytaniu, a te pochodzą z bazy danych, jedyną inną opcją jest wybranie całego zestawu danych (zawierającego te wartości) z tabeli w PHP, uruchomić go przez wersję PHP funkcji i zasadniczo uruchomić chrupanie numerów (które bazy danych są zaprojektowane do wydajnego działania) w PHP (co jest znacznie wolniejsze). Następnie masz dodatkowy narzut przeniesienia danych z bazy danych do PHP. Jest to optymalne rozwiązanie, ale oczywiście zwiększa złożoność. – Andy

1

Z pewnością można napisać funkcję MySQL, aby to zrobić. Nie mam czasu, aby napisać teraz, ale tu, gdzie zacząć.

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

+0

Oops Myślałem, że chcesz wziąć swoją funkcję php i przekształcić ją w funkcję MySQL. Przepraszam! –

+0

Była kolejna odpowiedź, która pokazała jak wywołać funkcję za pomocą ". Function_ame()." Składnia, która jest również wykonalna, jeśli chcesz zachować swoją funkcję w PHP. –

0

Ponieważ funkcje nie działają w cudzysłowie "lub" trzeba podzielić go z kropką (.)

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

Nadzieja to pomaga :)

+0

Jak wspomniano powyżej @thedaian, to nie zadziała jako 'lat' i' lon' są zmiennymi w instrukcji SELECT. –

1

MySQL przechowywane procedury http://dev.mysql.com/doc/refman/5.0/en/stored-routines.html

Niektóre funkcje mogą być różne, na Na przykład mysql równoważny z deg2rad php to funkcja radians() mysql'a. Myślę, że powinieneś być w stanie stworzyć równoważną funkcję. Przy takim podejściu należy mieć świadomość, że za każdym razem te zapytania będą wymagały tabelarycznego wyświetlania całej tabeli kodów zip.

Powiązane problemy