2011-08-26 17 views
8

Ho appena iniziato a utilizzare MySQL con PHP e mi piacerebbe sapere se è possibile creare una funzione personalizzata. Questo snippet di codice dovrebbe illustrare ciò che sto cercando di fare.Creazione di una funzione MySQL personalizzata?

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

Grazie in anticipo per qualsiasi aiuto!

+1

Proprio A proposito, si può fare perfettamente trovano da una query. Infatti, se si utilizza un indice spaziale basato sul proprio lat/lngs e si scoprirà che i risultati sono impressionanti. Incredibile infatti. – Layke

+0

Non sono sicuro di cosa intendi, potresti approfondire? Anche per "inadatto" non intendevo in termini di prestazioni (non ne so nulla); Intendevo con quanta pazienza sarebbe stata la domanda. –

risposta

12

Si dichiara questa funzione MySQL nell'applicazione e rimarrà nel database fino al riavvio del server di database.

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

Questo utilizza mathematical functions di MySQL. Lo scaricamento di questa elaborazione nel database è rapido ed efficiente (i dati non devono viaggiare attraverso il filo e vengono restituiti solo i risultati desiderati).

Una volta che hai dichiarato questo, è possibile utilizzarlo in questo modo:

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

Tuttavia, se il database non si riavvia, tutte le funzioni o procedure dichiarate in precedenza sono persi. È possibile gestire l'errore MySQL 1305 (Function functionName does not exist) con garbo a livello di applicazione.

Nel vostro gestore di errore del database:

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

Questa è l'unica opzione? Preferisco tenerlo limitato a PHP al momento. Aspetterò qualche altro minuto per segnare una risposta. –

+0

yeh immagino che non stia succedendo. Ho intenzione di andare con questo, +1. Acclamazione amico. –

+1

Poiché si utilizzano i valori 'lat' e' lon' nella chiamata di funzione 'Distance()' nella query, e questi provengono dal database, l'unica altra opzione è selezionare l'intero set di dati (contenente tali valori) da la tabella in PHP, eseguirla attraverso la versione PHP della funzione ed essenzialmente eseguire il numero-crunch (che i database sono progettati per funzionare in modo efficiente) in PHP (che è molto più lento). A questo punto si aggiunge il sovraccarico del trasferimento dei dati dal database a PHP. Questa è la soluzione ottimale, ma ovviamente aggiunge complessità. – Andy

1

È possibile scrivere una funzione MySQL per eseguire questa operazione. Non ho tempo di scrivere uno ora, ma ecco dove iniziare:.

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

+0

Oops Pensavo volessi prendere la tua funzione php e trasformarla in una funzione MySQL. Scusate! –

+0

C'era un'altra risposta che mostrava come chiamare la funzione usando ". Function_ame()". sintassi che è anche fattibile se vuoi mantenere la tua funzione in PHP. –

0

Poiché le funzioni non funzionano tra virgolette "o 'bisogna dividerlo con un punto (.)

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

Spero che questo aiuti :)

routine
+0

Come @thedaian ha dichiarato sopra, questo non funzionerà come 'lat' e' lon' sono variabili nell'istruzione SELECT. –

1

Mysql ha memorizzati http://dev.mysql.com/doc/refman/5.0/en/stored-routines.html

Alcune funzioni possono essere diverse, per Ad esempio, mysql equivalente a deg2rad di php è la funzione di rads() di mysql. Penso che dovresti essere in grado di creare una funzione equivalente. Con questo approccio, è necessario essere consapevoli che queste query dovranno eseguire tabelle per l'intera tabella di codici di avviamento ogni volta.

Problemi correlati