Function in Datenbankabrage

Sascha1976

Mitglied
Hallo,
ich habe folgendes Problem.

Ich möchte in einer Online Liste die Sortierung anhand der entfernung vornehmen.

Also User a wohnt von User b 62 km weg.

Dann soll in der Online Liste

User B --> 0 km
User A --> 62 km

erscheinen.

Aber wie kann ich das realisieren ?

Das ist die Datenbankabfrage:
PHP:
        $onuser_query =db_query("SELECT
                             s.*,
                             u.*
                         FROM
                             " . session . " s LEFT JOIN
                             " . users . " u USING(user_id)
                         WHERE
                           s.lastrefresh > '".$showslivetime."' and s.user_id > '0'
                         ORDER BY
                            u.user_pcode");

Die entfernung berechne ich folgender function
PHP:
$geo1_distance = geo_distance($geo1_latitude, $geo1_longitude, $geo2_latitude, $geo2_longitude);

PHP:
$geo1_latitude = Breitengrad User A
$geo1_longitude = Längengrad User A
$geo2_latitude = Breitengrad User B
$geo2_longitude = Längengrad User B


Wie baue ich diese function in die Datenbankabfrage mit ein und mache dann die Sortierung ?


Gruß
Sascha
 
Meines Wissens kann man keine PHP-Funktion direkt im SQL-Query ausführen lassen.
Du müsstest die Funktion also in SQL-Syntax nochmal schreiben.

Ich versuche mich mal:

Basis sind zwei von mir geschriebene Delphi-Funktionen (die Werte Lat und Lon kommen aus dem Objekt vom Typ TNauticPosition):
Code:
 function TNauticPosition.calcE(toLat,toLon:double):double;
  var e:double;
      La1,toLa2,Lo1,toLo2:double;
  begin
    Lo1:=Lon/360*2*PI;
    toLo2:=toLon/360*2*PI;
    La1:=Lat/360*2*PI;
    toLa2:=toLat/360*2*PI;
    e:=(sin(La1)*sin(toLa2))+(cos(La1)*cos(toLa2)*cos(toLo2-Lo1));
    calcE:=ArcTan (sqrt (1-sqr (e)) /e);
  end;

 function TNauticPosition.distTo(toPos:TNauticPosition):double;
  var e:double;
   begin
    e:=calcE(toPos.Lat,toPos.Lon);
    distTo:=abs( 3440.1841*2*PI* (360/(2*PI)*e))/360;
   end;


Nun zur Umwandlung in SQL-Syntax, zunächst ein kurzes Symbolverzeichnis, welches nicht zum Code gehört:

Symbole:

Lat: Abkürzung für Latitude
Lon: Abkürzung für Latitude
Datentyp: jeweils als DOUBLE
Plus : East/North
Minus: West/South

Lat: Latitude von User1 als Double
Lon: Longitude von User1 als Double
toLat: Latitude von User2 als Double
toLon: Longitude von User2 als Double
evtl. musst Du diese mit einem "(SELECT) User1.Latitude AS Lat" erst generieren
im schlimmsten Fall, müsstest Du Dir noch überlegen, wie die Du das Double aus dem typischen Grad°Minuten:Sekunden,Sekundenbruchteile-Format erzeugst.



Achtung: jetzt der Code (kann länger werden):

Code:
SELECT 
(Lon/360*2*PI()) AS Lo1,
(toLon/360*2*PI()) AS toLo2,
(Lat/360*2*PI()) AS La1,
(toLat/360*2*PI()) AS toLa2,
((SIN(La1)*SIN(toLa2))+(COS(La1)*COS(toLa2)*COS(toLo2-Lo1))) AS eTemp,
(ATAN (SQRT(1-(e*e)) /e)) AS e,
(ABS( 3440.1841*2*PI()* (360/(2*PI())*e))/360) AS distance,

weitereFelderDieDeinQueryAuslesenSoll

FROM

.....

ORDER BY distance;

Evtl. musst Du einzelne Funktionen nochmal hier nachschlagen.

Wenn das mit diesen ganzen AS nicht richtig hinhaut, könntest Du auch versuchen, alles in eine einzige Funktion zu pressen, allerdings wird dann eine Menge doppelt berechnet.

Gruß hpvw
 
Hallo,
danke für deine Antwort. Nur leider blicke ich da nicht durch.

Hier mal der komplette Code den ich habe.

PHP:
<?PHP
  include('./global.php');


 if($session['user_id']=="0") {
 Header("Location: start.php");
 }



function geo_distance ($longitude_1, $latitude_1, $longitude_2, $latitude_2)
{
	$earth_radius = 6378137.0;

	$long1 = deg2rad ($longitude_1);
	$long2 = deg2rad ($longitude_2);
	$lat1 = deg2rad ($latitude_1);
	$lat2 = deg2rad ($latitude_2);

    $dlon = $long2 - $long1;
    $dlat = $lat2 - $lat1;
    $a = pow( sin($dlat / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($dlon / 2), 2);
    $d = 2 * atan2(sqrt($a), sqrt(1 - $a));

    return $earth_radius * $d;
}


function distance_string($distance_meters)
{
	return round($distance_meters/1000).' '."Km";
}


 $navtext = "Wer ist gerade Online ?";
 $smarty->assign('navtext',$navtext);



 $geo1_query = db_query("select * from " . users . " where user_id = '".$session['user_id']."'");
 $geo1_data = db_fetch_array($geo1_query);
 $geo1_longitude=$geo1_data['user_longitude'];
 $geo1_latitude=$geo1_data['user_latitude'];


        $onuser_query =db_query("SELECT * FROM " . users . " WHERE user_gender = 1");

        while ($onuser_data = db_fetch_array($onuser_query)) {


$user_id=$onuser_data['user_id'];
$user_membername=$onuser_data['user_membername'];
$user_longitude=$onuser_data['user_longitude'];
$user_latitude=$onuser_data['user_latitude'];

 $geo2_query = db_query("select * from " . users . " where user_id = '".$user_id."'");
 $geo2_data = db_fetch_array($geo2_query);
 $geo2_longitude=$geo2_data['user_longitude'];
 $geo2_latitude=$geo2_data['user_latitude'];

 $geo1_distance = geo_distance($geo1_latitude, $geo1_longitude, $geo2_latitude, $geo2_longitude);
 $geo2_distance = distance_string($geo1_distance);

 $geo3_distance = geo_distance($geo1_latitude, $geo1_longitude, $user_latitude, $user_longitude);
 $geo4_distance = distance_string($geo3_distance);








$onlineuser .="$user_membername - $geo2_distance entfernt";
$onlineuser .="<br>";

}


  $smarty->assign('onlineuser',$onlineuser);
  $main_content=$smarty->fetch('online2.tpl');
  $smarty->assign('main_content',$main_content);
  $smarty->display('index.tpl');




?>

Vieleicht hast du ja noch eine andere möglichkeit wie ich das machen kann, vieleicht über arrays und diese dann Sortieren oder so.

Bin über jeden Hinweis und Hilfe dankbar.

So sieht es jetzt aus:
Sascha-Karen - 0 Km entfernt
wir2_23u21 - 62 Km entfernt
erftkreispaar - 5737 Km entfernt
Edel & heinz - 5737 Km entfernt
buzzel - 5737 Km entfernt
Naddl009 - 62 Km entfernt
PaarGe - 5737 Km entfernt
biggiklaus - 5737 Km entfernt
nico82298 - 5737 Km entfernt
klausbiggi - 5737 Km entfernt
Paar-Rhein-Sieg - 5737 Km entfernt


Und so soll es aussehen:
Sascha-Karen - 0 Km entfernt
wir2_23u21 - 62 Km entfernt
Naddl009 - 62 Km entfernt
erftkreispaar - 5737 Km entfernt
Edel & heinz - 5737 Km entfernt
buzzel - 5737 Km entfernt
PaarGe - 5737 Km entfernt
biggiklaus - 5737 Km entfernt
nico82298 - 5737 Km entfernt
klausbiggi - 5737 Km entfernt
Paar-Rhein-Sieg - 5737 Km entfernt


Gruß
Sascha
 
Zuletzt bearbeitet:
Ich habe nur jede einzelne Anweisung/Zuweisung meiner bekannten Funktion in SQL geschrieben.
Das kannst Du mit Deiner Funktion genau so machen.
Die Zuweisung ist halt nicht $variable=ausdruck, sondern ausdruck AS variable.
Dann kannst Du in dem Query direkt sortieren. Und Du musst die evtl. die Funktionesnamen anpassen.
Ansonsten könntest Du alles in ein Array schreiben und mit [phpf]usort[/phpf] sortieren.

Die Unterschiede zwischen den Formeln:

Ich habe den Erddurchmesser in nautischen Meilen, Du hast ihn in Meter.
Du wandelst mit einer Funktion in rad um, ich habe die Funktion ausgeschrieben.
Dann unterscheiden sich die Formeln evtl ein bisschen, da steig ich durch die Mathematik auch nicht so richtig durch. Ich denke, sie ergeben dasselbe Ergebnis oder berechnest Du die Entfernung bei gleichbleibendem Kurs? Ich berechne die kürzeste Distanz, also der Grund, warum die Titanic soweit nördlich einen Bogen gefahren ist und auf den Eisberg geknallt ist.

Vielleicht schreibst Du etwas konkreter, was Du nicht verstehst?

Gruß hpvw

PS: Wenn Du Deinen Code einrückst, dann ist er besser zu lesen.

EDIT: Ja, das mit der Ausgabe habe ich mir schon so gedacht ;)
 
So, ich habe mich mal über Deinen Code hergemacht, da ist ja ganz schön viel doppelt gewesen, vor allem viel zu viele Querys.
Versuche mal folgenden Code:
PHP:
<?PHP
    include('./global.php');

    if($session['user_id']=="0") {
        Header("Location: start.php");
    }

    $navtext = "Wer ist gerade Online ?";
    $smarty->assign('navtext',$navtext);

    $geo1_query = db_query("select * from " . users . " where user_id = '".$session['user_id']."'");
    $geo1_data = db_fetch_array($geo1_query);
    $geo1_longitude=$geo1_data['user_longitude'];
    $geo1_latitude=$geo1_data['user_latitude'];

    $onuser_query =db_query("SELECT
        user_id,
        ".$geo1_longitude." AS Lon,
        ".$geo1_latitude." AS Lat,
        user_membername,
        user_longitude AS toLon,
        user_latitude AS toLat,
        (Lon/360*2*PI()) AS Lo1,
        (toLon/360*2*PI()) AS toLo2,
        (Lat/360*2*PI()) AS La1,
        (toLat/360*2*PI()) AS toLa2,
        ((SIN(La1)*SIN(toLa2))+(COS(La1)*COS(toLa2)*COS(toLo2-Lo1)))
        AS eTemp,
        (ATAN (SQRT(1-(eTemp*eTemp)) /eTemp)) AS e,
        (ROUND((ABS( 6378137*2*PI()* (360/(2*PI())*e))/360))/1000),0)
        AS distance
        FROM " . users . " WHERE user_gender = 1 
        ORDER BY distance");

    $error=mysql_error();
    if (!empty($error)) {echo $error;}

    while ($onuser_data = db_fetch_array($onuser_query)) {
        $onlineuser .=$onuser_data['user_membername']." - ".$onuser_data['distance']." km entfernt";
        $onlineuser .="<br>\n";
    }

    $smarty->assign('onlineuser',$onlineuser);
    $main_content=$smarty->fetch('online2.tpl');
    $smarty->assign('main_content',$main_content);
    $smarty->display('index.tpl');

?>
ACHTUNG: Mach 'ne eigene Datei, ich habe aus Deinem Code eine Menge entfernt!
Ich habe mal die Funktion von mir verwendet und die nautischen Meilen in Meter geändert.
Wenn Du die 0 vor AS distance in eine Zahl größer 0 verwandelst erhältst Du auch Nachkommastellen zu deiner Entfernung.

Ach ja: Bitte schreib mir die Fehlermeldung, da gibt es bestimmt eine, ich habe es nicht getestet!
 
Danke für die Hilfe.

Die fehlermeldung:
Code:
1064 - You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '(SQRT(1-(eTemp*eTemp)) /eTemp)) AS e, (ROUND((ABS( 637

SELECT user_id, 6.76667 AS Lon, 51.2167 AS Lat, user_membername, user_longitude AS toLon, user_latitude AS toLat, (Lon/360*2*PI()) AS Lo1, (toLon/360*2*PI()) AS toLo2, (Lat/360*2*PI()) AS La1, (toLat/360*2*PI()) AS toLa2, ((SIN(La1)*SIN(toLa2))+(COS(La1)*COS(toLa2)*COS(toLo2-Lo1))) AS eTemp, (ATAN (SQRT(1-(eTemp*eTemp)) /eTemp)) AS e, (ROUND((ABS( 6378137*2*PI()* (360/(2*PI())*e))/360))/1000),0) AS distance FROM users WHERE user_gender = 1 ORDER BY distance

[SQL Error]

Gruß
Sascha
 
Versuch mal das Leerzeichen nach ATAN wegzunehmen.
Ich kann mir zwar schwer vorstellen, dass das hilft, aber ein Versuch ist es Wert.
 
Hat leider nichts gebracht, immer noch die selbe fehlermeldung.

Wie sieht das den aus, wenn ich alles in ein array schreibe, wie erfolgt dann die sortierung ?

PHP Datei:
PHP:
<?PHP
  include('./global.php');
 if($session['user_id']=="0") {
 Header("Location: start.php");
 }
function geo_distance ($longitude_1, $latitude_1, $longitude_2, $latitude_2)
{
	$earth_radius = 6378137.0;

	$long1 = deg2rad ($longitude_1);
	$long2 = deg2rad ($longitude_2);
	$lat1 = deg2rad ($latitude_1);
	$lat2 = deg2rad ($latitude_2);

    $dlon = $long2 - $long1;
    $dlat = $lat2 - $lat1;
    $a = pow( sin($dlat / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($dlon / 2), 2);
    $d = 2 * atan2(sqrt($a), sqrt(1 - $a));

    return $earth_radius * $d;
}
function distance_string($distance_meters)
{
	return round($distance_meters/1000).' '."Km";
}
 $navtext = "Wer ist gerade Online ?";
 $smarty->assign('navtext',$navtext);
 $geo1_query = db_query("select * from " . users . " where user_id = '".$session['user_id']."'");
 $geo1_data = db_fetch_array($geo1_query);
 $geo1_longitude=$geo1_data['user_longitude'];
 $geo1_latitude=$geo1_data['user_latitude'];
        $onuser_query =db_query("SELECT * FROM " . users . " WHERE user_gender = 1");
        while ($onuser_data = db_fetch_array($onuser_query)) {
$user_id=$onuser_data['user_id'];
$user_membername=$onuser_data['user_membername'];
$user_longitude=$onuser_data['user_longitude'];
$user_latitude=$onuser_data['user_latitude'];
 $geo2_query = db_query("select * from " . users . " where user_id = '".$user_id."'");
 $geo2_data = db_fetch_array($geo2_query);
 $geo2_longitude=$geo2_data['user_longitude'];
 $geo2_latitude=$geo2_data['user_latitude'];
 $geo1_distance = geo_distance($geo1_latitude, $geo1_longitude, $geo2_latitude, $geo2_longitude);
 $geo2_distance = distance_string($geo1_distance);
 $geo3_distance = geo_distance($geo1_latitude, $geo1_longitude, $user_latitude, $user_longitude);
 $geo4_distance = distance_string($geo3_distance);
      $module_content[]=array(
      				'GEO4'=>$geo4_distance,
                    'USER_ID'=>$onuser_data['user_membername']);

  $smarty->assign('module_content',$module_content);
}
  $smarty->assign('onlineuser',$onlineuser);
  $main_content=$smarty->fetch('online2.tpl');
  $smarty->assign('main_content',$main_content);
  $smarty->display('index.tpl');
?>


Html Datei:
HTML:
{foreach name=aussen from=$module_content item=module_data}
{$module_data.USER_ID} - {$module_data.GEO4}<br>
{/foreach}


GEO4 ist ja der errechnete wert, von der entfernung.

Sascha-Karen - 0 Km <---- Von hier aus, werden die entfernungen berechnet. $geo2_distance = 0 Km
wir2_23u21 - 62 Km
erftkreispaar - 5737 Km
Edel & heinz - 5737 Km
buzzel - 5737 Km
Naddl009 - 62 Km
PaarGe - 5737 Km
biggiklaus - 5737 Km
nico82298 - 5737 Km
klausbiggi - 5737 Km
Paar-Rhein-Sieg - 5737 Km

Gruß
Sascha
 
Hab das jetzt wie folgt gemacht:
PHP:
<?PHP
  include('./global.php');
 if($session['user_id']=="0") {
 Header("Location: start.php");
 }
function geo_distance ($longitude_1, $latitude_1, $longitude_2, $latitude_2)
{
	$earth_radius = 6378137.0;

	$long1 = deg2rad ($longitude_1);
	$long2 = deg2rad ($longitude_2);
	$lat1 = deg2rad ($latitude_1);
	$lat2 = deg2rad ($latitude_2);

    $dlon = $long2 - $long1;
    $dlat = $lat2 - $lat1;
    $a = pow( sin($dlat / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($dlon / 2), 2);
    $d = 2 * atan2(sqrt($a), sqrt(1 - $a));

    return $earth_radius * $d;
}
function distance_string($distance_meters)
{
	return round($distance_meters/1000).' '."Km";
}
 $navtext = "Wer ist gerade Online ?";
 $smarty->assign('navtext',$navtext);
 $geo1_query = db_query("select * from " . users . " where user_id = '".$session['user_id']."'");
 $geo1_data = db_fetch_array($geo1_query);
 $geo1_longitude=$geo1_data['user_longitude'];
 $geo1_latitude=$geo1_data['user_latitude'];
        $onuser_query =db_query("SELECT * FROM " . users . " WHERE user_gender = 1");
        while ($onuser_data = db_fetch_array($onuser_query)) {
$user_id=$onuser_data['user_id'];
$user_membername=$onuser_data['user_membername'];
$user_longitude=$onuser_data['user_longitude'];
$user_latitude=$onuser_data['user_latitude'];
 $geo2_query = db_query("select * from " . users . " where user_id = '".$user_id."'");
 $geo2_data = db_fetch_array($geo2_query);
 $geo2_longitude=$geo2_data['user_longitude'];
 $geo2_latitude=$geo2_data['user_latitude'];
 $geo1_distance = geo_distance($geo1_latitude, $geo1_longitude, $geo2_latitude, $geo2_longitude);
 $geo2_distance = distance_string($geo1_distance);
 $geo3_distance = geo_distance($geo1_latitude, $geo1_longitude, $user_latitude, $user_longitude);
 $geo4_distance = distance_string($geo3_distance);
      $module_content[]=array(
      				'GEO4'=>$geo4_distance,
                    'USER_ID'=>$onuser_data['user_membername']);
}
function cmp ($a, $b) { 
   $vergleich = (strcmp($a["GEO4"], $b["GEO4"]) == 1) ? -1 : 1;
   return $vergleich; 
} 


usort($module_content, "cmp");

  $smarty->assign('module_content',$module_content);

  $smarty->assign('onlineuser',$onlineuser);
  $main_content=$smarty->fetch('online2.tpl');
  $smarty->assign('main_content',$main_content);
  $smarty->display('index.tpl');
?>

Jetzt bekomm ich das wie folgt angezeigt.

wir2_23u21 - 62 Km
Naddl009 - 62 Km
buzzel - 5737 Km
Edel & heinz - 5737 Km
PaarGe - 5737 Km
erftkreispaar - 5737 Km
biggiklaus - 5737 Km
nico82298 - 5737 Km
klausbiggi - 5737 Km
Paar-Rhein-Sieg - 5737 Km
Sascha-Karen - 0 Km


Aber wie bekomm ich die 0 nach ganz oben ?

Gruß
Sascha
 
Ich habe noch einen Klammerfehler entdeckt:
Falsch:
Code:
        (ATAN(SQRT(1-(eTemp*eTemp)) /eTemp)) AS e,
        (ROUND((ABS( 6378137*2*PI()* (360/(2*PI())*e))/360))/1000),0)
        AS distance

Richtig:
Code:
        (ATAN(SQRT(1-(eTemp*eTemp)) /eTemp)) AS e,
        (ROUND((ABS( 6378137*2*PI()* (360/(2*PI())*e))/360)/1000),0)
        AS distance
Das da was fett ist, nämlich da, wo es sich unterscheidet, ist kaum zu erkennen, aber Du wirst es schon finden.

EDIT: Wg. der Sortierung: Du gibts keinen Wert (0) für Gleichheit zurück, wer weiss, wie der Algorithmus arbeitet. Außerdem vergleichst Du Strings und nicht die Zahlen. Könnten Gründe für falsche Sortierung sein.
 
Zuletzt bearbeitet:
Zurück