Loadbalancer: Datenbankabfrage erweitern - bitte um Hilfe!

Hallo zusammen,

mit folgendem Codeabschnitt frage ich alle Einträge einer mySQL-Tabelle von "A bis Z" ab. Hat jemand eine Idee, wie ich die Schleife so erweitern kann, dass auch noch alle Einträge, die mit einer Zahl (0 bis 9) beginnen, abgefragt werden? Falls jemand noch allgemeine Tipps hat, nehme ich die sehr gerne an (nur bitte eindeutig formulieren, siehe unten!).

Hier der Code:

---schnipp---
 for ($letter = A; $letter <> AA; $letter++)
  {
    $query="select title from $mytable where title like '$letter%' order by title";
   $result = @mysql_db_query($dbname,$query,$db) or die(mysql_error());
   $count=0;
    while ($row = mysql_fetch_row($result))
   {
     $count=1;
     $title=$row[0];
      $t = urlencode($title);
      $title=str_replace("<br>","",$title);
             echo $title;
    }
   if ($count==0)
    echo "Keine Einträge";
  }
---schnipp---

Ich hatte diese Frage in ähnlicher Form vor einiger Zeit schonmal gestellt, jedoch leider nur eine wenig hilfreiche Antwort bekommen, mit der ich als NICHT-Programmierer nicht viel anfangen konnte. Der obige Code wurde mal für ein Projekt entwickelt, welches ich betreue; ich bin kein PHP-Programmierer und will es - aufgrund fehlender Zeit - auch nicht unbedingt werden, da ich bereits genug andere Dinge machen muss. Trotzdem bin ich natürlich lernwillig.

Über Hilfe würde ich mich sehr freuen! :)

  1. hi,

    mit folgendem Codeabschnitt frage ich alle Einträge einer mySQL-Tabelle von "A bis Z" ab. Hat jemand eine Idee, wie ich die Schleife so erweitern kann, dass auch noch alle Einträge, die mit einer Zahl (0 bis 9) beginnen, abgefragt werden?

    for ($letter = A; $letter <> AA; $letter++)

    Hast du Konstanten namens A und AA definiert - oder meinst du die String 'A' und 'AA'?

    Da die Ziffern sich an anderer "Stelle" im Zeichnsatz befinden, geht das hier so nicht direkt.
    (Du könntest natürlich die Schleife bei '0' starten lassen, und in der Schleife dann Abfragen, ob der Wert '9' erreicht wurde - und dann $i auf 'A' setzen ...)

    Aber generell ist das Vorgehen suboptimal.
    Du willst ja offenbar alle Datensätze (zumindest die mit Buchtstaben oder Ziffern am Anfang des Wertes von title) abfragen - dafür dann aber in x Schleifendurchläufen jeweils eine neue Abfrage zu starten, ist unperformant.
    Da frag doch lieber alle gleich auf einmal ab, sortiere sie - und gebe sie dann in einer while-Schleife aus.
    Wenn du dabei Zwischenüberschriften o.ä. erzeugen willst, lautet dein Stichwort Gruppenwechsel. Und auch auf "nicht vorkommende" Anfangszeichen könnte man dabei reagieren, wenn gewünscht.

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
    1. Hallo,

      danke für Deine Antwort! Leider habe ich nicht alles verstanden, was Du meinst (wie gesagt, habe kaum Ahnung von PHP und möchte nur ein bestehendes Skript minimal erweitern). Trotzdem versuch's ich jetzt mal :)

      for ($letter = A; $letter <> AA; $letter++)

      Hast du Konstanten namens A und AA definiert - oder meinst du die String 'A' und 'AA'?

      Definiert ist überhalb des Codeabschnittes nichts.

      Aber generell ist das Vorgehen suboptimal.

      Ja, hatte ich schon befürchtet. Derjenige, der den Code seinerzeit (so um die PHP3-Zeit) erstellt hat, hatte auch nicht viel Ahnung.

      Du willst ja offenbar alle Datensätze (zumindest die mit Buchtstaben oder Ziffern am Anfang des Wertes von title) abfragen - dafür dann aber in x Schleifendurchläufen jeweils eine neue Abfrage zu starten, ist unperformant.

      Ok, ich habe eine bzw. mehrere mySQL-Tabellen, die etwa so aufgebaut sind:

      2 Freunde in Mexiko
      15 Minuten bis Mitternacht
      Am schmalen Strand
      Brüder wie wir
      [...]

      Ich möchte also alle Einträge von 0-9 und von A-Z abfragen und per echo ausgeben, wobei nach jedem Abschnitt eine Überschrift folgen soll, also so:

      -#-
      2 Freunde in Mexiko
      -A-
      Am schmalen Strand
      [...]

      Ich denke, dass ist es auch, was Du mit Zwischenüberschriften meinst. Nicht vorkommende Anfangszeichen (also andere als 0-9, A-Z gibt es nicht).

      Wenn Du oder jemand mir hier ein funkt. Beispiel aufzeigen könntest, würde ich mich sehr freuen! :)
      Wie gesagt, mir sagt das meiste von dem leider nicht viel.

      Besten Dank!

      Grüße
      Loadbalancer

      1. yo,

        die erste frage, die geklärt werden muss, ob du überhaupt datensätze ausschließen willst. so wie es aussieht, willst du nämlich alle haben und dann wird die eine abfrage sehr einfach.

        den gruppenwechsel kann man gut über PHP lösen, man muss bei der ausgabe der einzelnen datensätze nur überprüfen, ob sich der anfangsbuchstabe geändert hat.

        Ilja

        1. Ja, richtig. Ich möchte alle Datensätze (Einträge) einer Tabelle abfragen und mittels echo-Befehl ausgeben. Alle Einträge in der Tabelle beginnen mit den Zeichen "0" - "9" bzw. "A" - "Z". Nach jeder Zahl bzw. jedem Buchstaben soll dann ein neuer Abschnitt beginnen:

          -#-
          -A-
          -B-

          Das ist wohl der gemeinte Gruppenwechsel, oder?

          Grüße
          Loadbalancer

          yo,

          die erste frage, die geklärt werden muss, ob du überhaupt datensätze ausschließen willst. so wie es aussieht, willst du nämlich alle haben und dann wird die eine abfrage sehr einfach.

          den gruppenwechsel kann man gut über PHP lösen, man muss bei der ausgabe der einzelnen datensätze nur überprüfen, ob sich der anfangsbuchstabe geändert hat.

          Ilja

          1. yo,

            Ja, richtig. Ich möchte alle Datensätze (Einträge) einer Tabelle abfragen und mittels echo-Befehl ausgeben.

            dann kannst du schon mal den kompletten LIKE teil in der abfrage weglassen, das ist schon mal gut und du hast auch nur eine abfrage.

            Das ist wohl der gemeinte Gruppenwechsel, oder?

            genau, in der schleife, welche die datensätze schritt für schritt ausgibt, dort speichert eine variable den ersten buchstaben des letzten datensatzes. unterscheidet sich dieser von dem aktuellen datensatz, dann erfolgt ein gruppenwechsel.

            Ilja

            1. Klingt gut. Kannst Du mir das evlt. anhand eines Beispielcodes zeigen? Ich habe, wie schon gesagt, leider keine Ahnung von PHP und möchte nur ein bestehendes Skript etwas anpassen bzw. die Serverlast verringern, ohne mich erst langwierig einarbeiten zu müssen.

              In diesem Sinne auch Dir und allen anderen Helfern hier im Forum ein großes Dankeschön!

              yo,

              Ja, richtig. Ich möchte alle Datensätze (Einträge) einer Tabelle abfragen und mittels echo-Befehl ausgeben.

              dann kannst du schon mal den kompletten LIKE teil in der abfrage weglassen, das ist schon mal gut und du hast auch nur eine abfrage.

              Das ist wohl der gemeinte Gruppenwechsel, oder?

              genau, in der schleife, welche die datensätze schritt für schritt ausgibt, dort speichert eine variable den ersten buchstaben des letzten datensatzes. unterscheidet sich dieser von dem aktuellen datensatz, dann erfolgt ein gruppenwechsel.

              Ilja

              1. hi,

                Klingt gut. Kannst Du mir das evlt. anhand eines Beispielcodes zeigen?

                  
                <?php  
                // deine Texte, hier statisch hinterlegt, werden später natürlich aus der Datenbank kommen  
                $texte = array('08/15', '007', '4321', '4 Freunde', 'ABC', 'aha', 'blubb', 'blah', 'Boing', 'Cäsar', 'Coyote', 'chemisch', 'Dynamit');  
                  
                // Initialisierung des Vergleichswertes mit einem Wert, der in den Daten garantiert nicht vorkommt:  
                // Einen Leerstring hat garantiert keiner der Texte als erstes "Zeichen"  
                $vorherigesErstesZeichen = '';  
                  
                // Schleife über die Daten - wegen Array hier foreach, wenn du das für die Ausgabe der  
                // Datensätze aus der DB anpasst, bietet sich idR. eine while-Schleife eher an  
                foreach($texte as $text) {  
                    // Erstes Zeichen des aktuell auszugebenden Textes ermitteln, und ggf. in einen  
                    // Kleinbuchstaben umwandeln (kann entfallen, wenn mit "a" und mit "A" beginnende  
                    // Texte separat aufgelistet werden sollen  
                    $aktuellesErstesZeichen = strtolower($text{0});  
                    // Vergleichen, ob das aktuelle erste Zeichen ungleich dem des vorherigen Datensatzes ist  
                    if($aktuellesErstesZeichen !== $vorherigesErstesZeichen) {  
                        // Wenn ja, Zwischenüberschrift ausgeben  
                        echo '<h1>Jetzt folgen die Einträge mit dem Anfangszeichen "'.$aktuellesErstesZeichen.'"</h1>';  
                    }  
                    // Den eigentlichen Text ausgeben  
                    echo $text.'<br>';  
                    // Vergleichswert für nächsten Schleifendurchlauf auf aktuelles erstes Zeichen aus  
                    // diesem Durchlauf setzen  
                    $vorherigesErstesZeichen = $aktuellesErstesZeichen;  
                }  
                ?>
                

                That's it, so simpel funktioniert ein (einstufiger) Gruppenwechsel.

                gruß,
                wahsaga

                --
                /voodoo.css:
                #GeorgeWBush { position:absolute; bottom:-6ft; }
                1. Hallo,

                  erstmal 1000 Dank, hast mir sehr geholfen! Das Skript funktioniert prima und dank der Kommentare ist es auch für einen totalen PHP-Laien wie mich recht gut nachzuvollziehen :)

                  Bei der Umsetzung habe ich jedoch ein kleines Problem:

                  Ich frage die DB so ab:
                  ---schnipp---
                  $query="select title from $mytable order by title";
                  $result = @mysql_db_query($dbname,$query,$db) or die(mysql_error());
                  ---schnapp---

                  Wenn ich jetzt mit Deiner Schleife (auf while geändert) die Titel aus $result ausgeben will, erhalte ich nur "Resource id #3" als Ausgabe.
                  Was läuft da falsch?

                  Grüße
                  Loadbalancer

                  1. hi,

                    Ich frage die DB so ab:
                    ---schnipp---
                    $query="select title from $mytable order by title";
                    $result = @mysql_db_query($dbname,$query,$db) or die(mysql_error());
                    ---schnapp---

                    Wenn ich jetzt mit Deiner Schleife (auf while geändert) die Titel aus $result ausgeben will, erhalte ich nur "Resource id #3" als Ausgabe.

                    Dann hast du noch nicht ganz verstanden, wie man das Ergebnis einer Datenbank-Abfrage ausliest.

                    Was läuft da falsch?

                    Nichts :-)

                    mysql_query (mysql_db_query solltest du nicht mehr verwenden, das ist veraltet) liefert dir eine "Resource ID" zurück, eine Art Nummer, unter der das Ergebnis einer erfolgreichen Abfrage ansprechbar ist.
                    Wenn du an die einzelnen Datensätze, die da "drin" sind, rankommen willst, musst du diese jetzt aber noch da raus holen, mit einer der mysql_fetch-Funktionen, zum Beispiel mit mysql_fetch_array(). Da diese Funktionen immer nur einen neuen Datensatz holen, musst du das dann aber noch in einer Schleife machen - siehe Beispiele auf der verlinkten Seite.

                    gruß,
                    wahsaga

                    --
                    /voodoo.css:
                    #GeorgeWBush { position:absolute; bottom:-6ft; }
                    1. echo $begrüßung;

                      mysql_query [...] liefert dir eine "Resource ID" zurück,

                      Ergänzend dazu: Eine "Resource ID" liefert es nur im Gut-Fall zurück. Im Fehlerfall liefert es false. false ist aber kein gültiges Argument für die Fetch-Funktionen. Es ist auch nicht sinnvoll, Datensätze lesen zu wollen, die wegen eines Fehlers gar nicht bereitgestellt wurden. Berücksichtige also im Programmablauf auch die Möglichkeit des Fehlschlagens.

                      echo "$verabschiedung $name";

                      1. Ich danke allen, die geholfen haben!
                        Werde mich jetzt mal dran machen, das neue Wissen einzubringen. Falls ich nicht weiterkomme, melde ich mich nochmal :)

                        Grüße
                        Loadbalancer

  2. Mach doch einfach zwei Schleifen...

    $count=0;
    for ($letter = A; $letter <> AA; $letter++)
      {
        $query="select title from $mytable where title like '$letter%' order by title";
       $result = @mysql_db_query($dbname,$query,$db) or die(mysql_error());
           while ($row = mysql_fetch_row($result))
       {
         $count=1;
         $title=$row[0];
          $t = urlencode($title);
          $title=str_replace("<br>","",$title);
                 echo $title;
        }
       if ($count==0)
        echo "Keine Einträge";
      }

    $count=0;
    for ($letter = 0; $letter <= 9; $letter++)
      {
        $query="select title from $mytable where title like '$letter%' order by title";
       $result = @mysql_db_query($dbname,$query,$db) or die(mysql_error());
           while ($row = mysql_fetch_row($result))
       {
         $count=1;
         $title=$row[0];
          $t = urlencode($title);
          $title=str_replace("<br>","",$title);
                 echo $title;
        }
       if ($count==0)
        echo "Keine Einträge";
      }

    1. Hallo,

      genau DAS ist z.Z. der Fall und ich möchte den Code gern etwas verschlanken/optimieren. Mir wurde ja auch schon gesagt, dass die ganze Abfrage sehr "unperfomant" sei.

      Grüße
      Loadbalancer

      Mach doch einfach zwei Schleifen...

      1. Du könntest dir auch die Schleife um die SQL-Abfrage sparen und gleich in der SQL-Abfrage nur die Datensätze herausfiltern, die du haben möchtest. Das sollte mit Hilfe regulärer Ausdrücke funktionieren:

        select title from $mytable where title like REGEXP '[A-Z]*' OR title like REGEXP '[0-9]*' order by title

        SQL-Anfrage ohne Gewähr, genaue Syntax gibts hier:
        http://dev.mysql.com/doc/refman/5.0/en/regexp.html

        Danach brauchst du dann nur noch eine Schleife, die alle Ergebnisse durchläuft und ausgibt.