Bernhard W.: SELECT und Namensliste übersichtlich halten (incl. mysql)

Hi, ich möchte mit einem SELECT-Objekt eine Namensliste mit Unterteilung der Anfangsbuchstaben der Vornamen erstellen. Also so in etwa:<br>
-------<br>
A<br>
  ein Name mit A<br>
  anderer Name mit A<br>
B<br>
  ein Namen mit B<br>
  anderer Name mit B<br>
-------<br>

Bisher habe ich den folgenden Code geschaft (wahrscheinlich etwas unelegant; bin nur Programmer-Praktikant *g*):<br>
<div id="adrfeld" ><br>
<? $abfr = "SELECT benutzer.vname , benutzer.name , benutzer.strasse , orte.ort<br>
   FROM benutzer LEFT JOIN orte ON benutzer.ort-nr = orte.id<br>
   ORDER BY benutzer.vname ASC";<br>
   $res = mysql_query($abfr);?><br>
  <form style="float:right"><br>
    <select name="Auswahl" size="20" style="border:0px; width:155px;"            <br>overflow:hidden;"onchange="showAddress(this.form.Auswahl.options[this.form.Auswahl.selectedIndex].value)"><br>
     <? while($ausg = mysql_fetch_object($res)) { $ind=$ausg->vname; <br>$index=$ind[0]; $initi=$ausg->name; ?><br>
        <optgroup label="<? echo $index;?> "><br>
        <option value="<? echo $ausg->strasse;?>, <? echo $ausg->ort;?>"><br>
        <? echo $ausg->vname;?> <? echo $initi[0];?>.</option> <br>
        </optgroup> <? } //while-ende ?><br>
     </select><br>
     <? mysql_free_result($res);?><br>
   </form><br>
   <p style="font-size:50%;i;text-align:right">f&uuml;r Anzeige Name ausw&auml;hlen</p><br>
</div>
Über die While-Schleife verarbeitet er mir zwar alles richtig, aber <br>halt bei jedem eintrag in die DB macht er auch eine neue <br>optgroup-Initiale.<br>
Wie könnte ich das ausbessern/verschachteln??<br>
Hoffe ihr könnt mir weiter helfen.<br>

  1. Braucht man jetzt diese "<br>" doch nicht?
    Des Absende-Formular hat was von "unübersichtlicher Darstellung"
    gemekert, da hab ich die <br>-s hinzugefügt.
    Also falls se unnötig waren einfach nicht beachten.
    Gruss

  2. Hallo Bernhard,

    A
      ein Name mit A
      anderer Name mit A
    B
      ein Namen mit B
      anderer Name mit B

    <? $abfr = "SELECT benutzer.vname , benutzer.name , benutzer.strasse , orte.ort<br>
       FROM benutzer LEFT JOIN orte ON benutzer.ort-nr = orte.id<br>
       ORDER BY benutzer.vname ASC";<br>

    meine erste Anmerkung:
    Verlasse Dich lieber nicht auf short_open_tag=on verlassen und statt dessen eine der beiden beschriebenen _immer_ funktionierenden Methoden verwenden, um PHP-Bereiche zu kennzeichnen.

    zweitens:
    Du benutzt nur die Spalten

    vname, name und strasse

    Deiner Abfrage. Deswegen ist es eine gute Idee, auch nur diese Felder abzufragen:

    SELECT  
        vname,        -- vollqualifizierte Spaltennamen sind nur erforderlich  
        name,         -- wenn diese innerhalb der Tabellen einer Abfrage  
        strasse       -- nicht eindeutig sind  
    FROM benutzer b   -- Aliasnamen helfen Schreibarbeit zu sparen  
    LEFT JOIN orte ON b.`ort-nr` = orte.id  -- Spalten mit Sonderzeichen  
                                            -- sind meist keine gute Idee  
                                            -- Das Minuszeichen hat eine  
                                            -- besondere Bedeutung :-)  
    ORDER BY vname    -- Aufsteigend ist die Standardsortierreihenfolge  
                      -- Das Semikolon am Ende der SQL-Anweisung solltest Du  
                      -- weglassen.
    

    $res = mysql_query($abfr);?>
      <form style="float:right">

    Ständiger Wechsel zwischen PHP- und HTML-Bereichen ist keine gute Idee.
    Speichere lieber vorher die Daten, die Deine Datenbankabfrage zurückliefert, in einem Array zwischen und schreibe dann z.B. mit echo das HTML.

    <br>$index=$ind[0]; $initi=$ausg->name; ?><br>

    <optgroup label="<? echo $index;?> "><br>

    Speichere den zuletzt ermittelten Anfangsbuchstaben in einer Variable.
    Überprüfe bei jedem Durchlauf, ob sich dieser geändert hat.
    Schreibe optgroup nur dann, wenn eine Änderung erfolgt.

    <p style="font-size:50%;i;text-align:right">f&uuml;r Anzeige Name ausw&auml;hlen</p><br>

    Inline-CSS macht den Code nicht lesbarer und erst recht nicht wartbarer. Nutze geeignete Selektoren. Die Lektüre von SELFHTML kann Dir dabei helfen. Eine geeignete Wahl der Zeichenkodierung macht übrigens die Verwendung von &uuml; und Konsorten überflüssig.

    Und nein, Du musst hier in der Textarea eine Zeile _nicht_ mit <br> abschließen. Es gibt übrigens eine Vorschau ;-)

    Freundliche Grüße

    Vinzenz

    1. Hallo Vinzenz

      Ständiger Wechsel zwischen PHP- und HTML-Bereichen ist keine gute Idee.

      Hab erst angefangen mit php und mysql zu arbeiten. Des ständige Wechseln zw. php und html macht die Quell-Datei auch recht unübersichtlich.
      Ich bemühe mich aber weiter.

      Speichere lieber vorher die Daten, die Deine Datenbankabfrage zurückliefert,

      in einem Array zwischen und schreibe dann z.B. mit echo das HTML.
      Ist das nicht etwas unpraktisch? Dadurch würd ich die Festplatte doch wegen einer kleinen Abfrage ziemlich belasten.
      Ists on-fly ned schneller und effizienter?

      Speichere den zuletzt ermittelten Anfangsbuchstaben in einer Variable.
      Überprüfe bei jedem Durchlauf, ob sich dieser geändert hat.
      Schreibe optgroup nur dann, wenn eine Änderung erfolgt.

      Genau an dieser Stelle habe ich ja mein Problem, ich weis nämlich nicht wie ich die Überprüfung hinkriege!!
      Wie sind meine Abfrage-Ausgaben eigentlich zwischengespeichert? Als Array oder Objekt?
      Was ist da der Unterschied? (Hab das fetch_object übers google'n gefunden und's läuft damit,
      wenn ich auf Array umstell beim Ausführen hauts nicht mehr hin.)

      1. Hallo Bernhard,

        Ist das nicht etwas unpraktisch? Dadurch würd ich die Festplatte doch wegen einer kleinen Abfrage ziemlich belasten.

        Festplattenzugriffe sollte es dabei keine geben.

        Ists on-fly ned schneller und effizienter?

        Wahrscheinlich weder noch. Effizienter Code ist übrigens auch wartbarer Code. Dein Code ist nicht wartbar.

        Wie sind meine Abfrage-Ausgaben eigentlich zwischengespeichert? Als Array oder Objekt?

        Lies bitte den entsprechenden Handbuchabschnitt.

        Speichere den zuletzt ermittelten Anfangsbuchstaben in einer Variable.
        Überprüfe bei jedem Durchlauf, ob sich dieser geändert hat.
        Schreibe optgroup nur dann, wenn eine Änderung erfolgt.

        Genau an dieser Stelle habe ich ja mein Problem, ich weis nämlich nicht wie ich die Überprüfung hinkriege!!

        Folgender Algorithmus könnte dies in etwa bewirken (sowas wie Pseudocode):

        Lies Deine Daten in ein zweidimensionales Array (Du könntest Dir dies als Tabelle vorstellen ein).
        Setze Letzter_Anfangsbuchstabe auf Leerstring
        Solange es noch Zeilen in Deinem Array gibt
           Ermittle den Anfangsbuchstaben des Namens
           Wenn dieser Anfangsbuchstabe ungleich Letzter_Anfangsbuchstabe ist
              Setze Letzter_Anfangsbuchstabe auf aktuellen Anfangsbuchstaben
              Schreibe Optgroup mit diesem Anfangsbuchstaben
           Ende Wenn
           Schreibe den Namenseintrag
           Hole die nächste Zeile
        Ende Solange

        Ich empfehle Dir ganz dringend, das PHP-Handbuch, das MySQL-Handbuch Deiner MySQL-Version und die PHP-FAQ in Deine Lesezeichen mitaufzunehmen. Ich wüßte nicht mehr, wie ich ohne diese auskäme.

        <anmerkung type="Godot">
        Bei Fragen zu MySQL ist es immer eine gute Idee, die genaue Version anzugeben, da sich der Leistungsumfang von MySQL sehr stark versionsbedingt unterscheidet. *bg*
        </anmerkung>

        Ach ja, SELECT (in Großbuchstaben) im Thema ist natürlich ein weiterer Faktor für die Bewertung als unsauberes Posting :-)

        Freundliche Grüße

        Vinzenz

    2. Ich hab für die Initialen ja schon die Variable $index, bräuchte also nur noch die Überprüfungsanweisung entwicklen und diese in der richtigen Form in die While-Schleife einbinden, oder so ähnlich :-)

      <p style="font-size:50%;text-align:right">f&uuml;r Anzeige Name ausw&auml;hlen</p><br>

      Dieses Absatz-Element ist übrigens nur als Fußnoten-Hinweistext und steht nicht in der Schleife.

  3. echo $begrüßung;

    Vinzenz hat ja schon eine Menge gesagt, ich gebe auch noch meinen Senf dazu, zu einem nicht unwichtigen Thema.

    $res = mysql_query($abfr);
       while($ausg = mysql_fetch_object($res))

    Ein gern gemachter Anfängerfehler ist, nur den Gutfall zu betrachten. Doch die Welt ist schlecht, die des Programmierers ganz besonders :-) Man will auf eine Datenbank zugreifen, aber das dumme Ding macht grad eine mit der Gewerkschaft nicht abgestimmte Pause. mysql_query() ist also nicht erfolgreich gewesen. Was macht es in so einem Fall? Das Handbuch klärt auf. Statt des erwarteten Ressourcen-Wertes liefert es false zurück. Nun soll mysql_fetch_object() an die Reihe kommen und das ist genau wie seine Geschwister mysql_fetch_array() usw. etepetete. Es mag nicht mit booleschen Werten gefüttert werden. Nur Ressourcen-Werte will es haben. Wenn es keinen solchen bekommt, beklagt es sich bitterlich und versaut das schöne HTML-Layout mit einer unformatierten Warnung.

    Was also tun? Fehlermeldungen auszuschalten oder zu unterdrücken ist die denkbar schlechteste Alternative. Gleich danach kommt das Sterbenlassen des Scripts, wenn ein Fehler auftrat. Das oft verwendete
      $res = mysql_query($sql) or die('Fehler aufgetreten: ' . mysql_error());
    ist zwar schnell hingeschrieben, aber sehr benutzerunfreundlich und eine wegen des Abbruchs unvollständig angezeigte Seite sieht auch nicht gerade professionell aus.

    Ein besserer Weg ist, sich das aus dem Tutorial <del>gekla</del>kopierte Beispiel genau anzusehen, und zu den verwendeten Funktionen die Beschreibung im Handbuch nachschlagen. Dort schaue man, was für Parameter die Funktion erwartet und welche Werte sie zurückliefert - sowohl im Gutfall als auch im Fehlerfall. Nun sollte man sich Gedanken machen, wie die Anwendung im Falle eines Fehlers reagieren soll. Diese Frage sollte man sich aus zwei Perspektiven stellen: Anwender und Systembetreiber. Während der Entwicklung ist es ohne Frage sinnvoll, sich den genauen Wortlaut des Fehlers anzuzeigen, doch wenn die Anwendung für die vorgesehenen Benutzer freigegeben wird sind solche Meldungstexte ob der gezeigten Information entweder unverständlich (DAU) oder gefährlich (böser Bube). Eine allgemein gültige, beste Verfahrensweise gibt es nicht. Vielmehr muss der Betreiber des Systems festlegen, was er gern in einem solchen Fall haben möchte. Drei Vorschläge wären:

    • Email mit Fehlertext an den Administrator senden.
    • Fehlermeldung in eine Log-Datei schreiben.
    • Nichts weiter, nur eine Tröstmeldung dem Anwender ausgeben.

    Auf jeden Fall aber sollte der Programmablauf so gestaltet werden, dass nicht aufgrund des einen Fehlers viele Folgefehler hinterher kommen.

    echo "$verabschiedung $name";