Kalle_B: Anzeigetafel: Mehrfache Einträge erkennen, zusammenfassen

Hallöle,

ich habe eine Seite gebaut, die Events ähnlich einer Abflugtafel auf Flughäfen anzeigt. Sie wird alle 60 sec aktualisiert. Mehrere gleichartige Events an einem Tag sollen aber nur eine Position beanspruchen. Ob das wohl mit einer geschickten SQL- Abfrage geht?

Was gemeint ist, seht ihr in Heidelberg am 13.06.2010. Das Solarboot fährt 6 mal am Tag und verdrängt dadurch andere Events von der Anzeige.

Ich möchte die Solarboot- Anzeige so:

10:00 Solarboot
      auch um 11:30, 13:00, 15:00, 16:30, 18:00

Allerdings stehen die gleichartigen Events nicht uhrzeitmäßig hintereinander, es können andere Events dazwischenkommen. Im Moment habe ich keine Idee, wie ich die Events zusammenfassen kann.

Das jetzige SQL- Kommando:

  $q = "  
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
# UMKREIS-ORTE MIT OEFFTL. VERANSTALTUNGEN LESEN  
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
SELECT  
 SQL_CALC_FOUND_ROWS  
 ter1.*  
,ter1.id                    TID  
,DATE_FORMAT(ter1.tag,'%w') wotag  
,ter1.geo_breite            ter_lat  
,ter1.geo_laenge            ter_lon  
  
,ort1.*  
,ort1.id            ORT  
,ort1.plz           ort_plz  
,ort1.name          ort_name  
  
,vtr1.id            VIP  
,vtr1.firma1        vtr_firma1  
  
,typ1.id            TYP  
,typ1.gruppe        typ_gruppe  
,typ1.name          typ_name  
  
-- dist = 6378.388 * acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1))  
-- 62831.853  
-- 6366.19773095  
,ROUND( 6366.19773095 * ACOS( SIN(".$rad_lat1.") *SIN(RADIANS(IF(ter1.geo_breite IS NULL,ort1.geo_breite,ter1.geo_breite))) +COS(".$rad_lat1.") *COS(RADIANS(IF(ter1.geo_breite IS NULL,ort1.geo_breite,ter1.geo_breite))) *COS(RADIANS(IF(ter1.geo_laenge IS NULL,ort1.geo_laenge,ter1.geo_laenge)) -".$rad_lon1." )) *1000.0) /1000.0 dist_km  
FROM      ".$db[0]['orte']." ort1  
         ,".$db[0]['termine']." ter1  
LEFT JOIN ".$db[0]['adressen']." vtr1  
ON        vtr1.id = ter1.veranstalter_id  
LEFT JOIN ".$db[0]['termintypen']." typ1  
ON        typ1.id = ter1.typ_id  
WHERE     ter1.ort_id = ort1.id AND ter1.intern_kz=0 AND ter1.tag >= '".$arr_in['tag_von']."' AND ter1.tag <= '".$arr_in['tag_bis']."'  
AND       ROUND( 6366.19773095 * ACOS( SIN(".$rad_lat1.") *SIN(RADIANS(IF(ter1.geo_breite IS NULL,ort1.geo_breite,ter1.geo_breite))) +COS(".$rad_lat1.") *COS(RADIANS(IF(ter1.geo_breite IS NULL,ort1.geo_breite,ter1.geo_breite))) *COS(RADIANS(IF(ter1.geo_laenge IS NULL,ort1.geo_laenge,ter1.geo_laenge)) -".$rad_lon1." )) *1000.0) /1000.0 < ".$arr_in['KM']."  
#ORDER BY  dist_km, ter1.tag, ter1.uhr  
ORDER BY  ter1.tag, ter1.uhr, dist_km  
LIMIT 0,20  
";  

Freue mich auf Ideen.

Gruß, Kalle

  1. Hallo,

    ich habe eine Seite gebaut, die Events ähnlich einer Abflugtafel auf Flughäfen anzeigt. Sie wird alle 60 sec aktualisiert. Mehrere gleichartige Events an einem Tag sollen aber nur eine Position beanspruchen. Ob das wohl mit einer geschickten SQL- Abfrage geht?

    Wenn es nur das wäre, würde ich z.B. GROUP BY titel vorschlagen. Aber es sollen ja alle Zeiten dargestellt werden...

    10:00 Solarboot
          auch um 11:30, 13:00, 15:00, 16:30, 18:00

    Ich Nehme an, dass du die Einträge über eine <table> darstellst. Ein "Haupteintrag" wäre dann z.B. folgende Zeile:
    <tr><td>10:00</td><td>Solarboot</td></tr>

    Bevor so eine Zeile geschrieben wird, gleichst du den aktuellen Array-Wert Titel (ich gehe hier davon aus, dass du dir das Mysql Ergebnis als Array ausgeben lässt und es dann dem Datum und der Uhrzeit nach durchgehst) mit den restlichen ab. Wenn nochmal der gleiche Titel vorkommt speicherst du dir die Zeit in eine temporäre Variable und löscht den jeweiligen Array-Eintrag.

    Wenn du dann in deiner temp. Variable ein Ergebnis hast, schreibt dein Skript dir erst noch z.B:
    <tr><td></td><td>Auch um 15:00 und 16:00</td></tr> rein. Ansonsten macht er gleich mit dem nächsten Array-Eintrag weiter.

    Ich hoffe, das war einigermßaen verständlich erklärt - sonst frag ruhig nochmal nach...
    Das war mein erster spontaner EInfall - es geht also sicher noch eleganter.

    Gruß
    Alex

    1. Hallo,

      Ich Nehme an, dass du die Einträge über eine <table> darstellst. Ein "Haupteintrag" wäre dann z.B. folgende Zeile:
      <tr><td>10:00</td><td>Solarboot</td></tr>

      Bevor so eine Zeile geschrieben wird, gleichst du den aktuellen Array-Wert Titel (ich gehe hier davon aus, dass du dir das Mysql Ergebnis als Array ausgeben lässt und es dann dem Datum und der Uhrzeit nach durchgehst) mit den restlichen ab. Wenn nochmal der gleiche Titel vorkommt speicherst du dir die Zeit in eine temporäre Variable und löscht den jeweiligen Array-Eintrag.

      Ist ein PHP- Ansatz. Programmtechnisch aber nicht ganz sauber, denn die "zusammengehörenden" Events eines Tages können ja weit auseinanderliegen, wenn viele andere Events uhrzeitlich dazwischen liegen.

      Das ist dann der Fall, wenn du du den Umkreis sehr groß machst, also Events von anderen Städten dazukommen.

      Ich wollte nur 20 Positionen (LIMIT 0,20) aus der DB lesen. Wieviele müssten es bei deinem Vorschlag sein?

      Wenn du dann in deiner temp. Variable ein Ergebnis hast, schreibt dein Skript dir erst noch z.B:
      <tr><td></td><td>Auch um 15:00 und 16:00</td></tr> rein. Ansonsten macht er gleich mit dem nächsten Array-Eintrag weiter.

      Ich hoffe, das war einigermßaen verständlich erklärt

      Ja, es ist eine PHP- Lösung. Gibt es noch Vorschläge für eine SQL- Lösung?

      Kalle

      1. Hallo,

        Ist ein PHP- Ansatz. Programmtechnisch aber nicht ganz sauber, denn die "zusammengehörenden" Events eines Tages können ja weit auseinanderliegen, wenn viele andere Events uhrzeitlich dazwischen liegen.

        Das ist dann der Fall, wenn du du den Umkreis sehr groß machst, also Events von anderen Städten dazukommen.

        Ich wollte nur 20 Positionen (LIMIT 0,20) aus der DB lesen. Wieviele müssten es bei deinem Vorschlag sein?

        Du musst immer aus allen Zeilen (des jeweiligen Tages und der jeweiligen Region) Werte auslesen, weil für die "auch um X Uhr" Angabe brauchst du diese ja. Ansonsten wäre es eben die GROUP BY Lösung, aber die verschlingt dir ja die anderen Uhrzeiten.

        Bei der Array Lösung würdes du nichts verlieren. Egal, wie viel dazwischen liegt. Bei vielen Daten kann das aber eventuell auf die Performance gehen - weiß ich nicht...

        Ja, es ist eine PHP- Lösung. Gibt es noch Vorschläge für eine SQL- Lösung?

        Du könntest dir über einen Subquery ein neues "Datenfeld" angeben lassen, in dem du die alternativen Uhrzeiten einfügst und dann im HauptQuery das Group By machen. Dann hat deine Datenbank aber noch mehr zu tun...

        Gruß
        Alex

  2. Du könntest dir die MySQL-Funktion GROUB_CONCAT() hierzu mal ansehen.

    1. Du könntest dir die MySQL-Funktion GROUB_CONCAT() hierzu mal ansehen.

      Hallo, DiBo33,

      interessanter Tipp, die Funktion kannte ich noch nicht. Damit bekomme ich tatsächlich alle Uhrzeiten des Tages zu einem Event und kann sie aufsteigend sortieren. Wenn ich die erste unterdrücke, habe ich wie gewünscht die weiteren.

      Aber durch die notwendige GROUP BY Klausel geht mir der Satzzusammenhang verloren. Für den Link zur Detaildarstellung brauche ich die ID des Satzes mit der kleinsten Uhrzeit. Das muss nicht unbedingt die kleinste ID der Gruppe sein.

      Also muss ich tricksen: Mit MIN(CONCAT (uhr,id)) fasse ich Uhrzeit und ID der Sätze zusammen und hole mit die zugehörige id.

      Die Performance ist akzeptabel. Von 0,06 auf 0.07 sec Programmdurchlaufzeit.

      Kalle