hossi: mySQL - Abfrage 2 Tabellen und Ausgabe als Baumstruktur

Guten Morgen,

ich habe hier gestern schon gepostet zu dem gleichen Thema, mit diesen  Nested-Set-Muster komme ich irgendwie nicht klar bzw. übersteigts meine Fähigkeiten. Mein Ziel ist es, ein Menü mit Baumstruktur auszugeben.

Nach etwas längerer Überlegung habe ich mir einen neuen Lösungsansatz ausgedacht, der in etwa so aussieht:

Ich habe eine Datenbank mit 2 Tabellen

oberkategorie (tabelle1)
ID       name
1        Sport
2        Auto
3        Essen

unterkategorie (tabelle2)
ID       name       oberkategorieID
1        Fußball     1
2        Baseball    1
3        BMW         2
4        Audi        2
5        Mercedes    2
6        Fastfood    3
7        Vegetarisch 3

Wie man erkennt, sollen die aus Tabelle2 eingetragenen Werte anhand der oberkategorieID (welche der ID von Tabelle1 entspricht) zugeordnet werden.

Danach möchte ich die Datensätze mit einem row-> in einer Tabelle ausgeben. Das sollte funktionieren, oder?

Die Baumstruktur sollte dann so aussehen:

  • Sport
    -- Fußball
    -- Baseball
  • Auto
    -- BMW
    -- AUDI
    -- Mercedes
  • Essen
    -- Fastfood
    -- Vegetarisch

Das einzige was mir fehlt, ist die MySQL Abfrage. Die muss über 2 Tabellen laufen und die Ausgabe von Tabelle2 oberkategorieID muss der ID in Tabelle 1 zugeordnet werden.

Wie Stelle ich das am besten (dümmsten) an?

Ist mein Vorhaben so überhaupt realistisch?

  1. Mahlzeit hossi,

    Danach möchte ich die Datensätze mit einem row-> in einer Tabelle ausgeben. Das sollte funktionieren, oder?

    Ja. Schleifen sind Dir ein Begriff?

    Das einzige was mir fehlt, ist die MySQL Abfrage. Die muss über 2 Tabellen laufen und die Ausgabe von Tabelle2 oberkategorieID muss der ID in Tabelle 1 zugeordnet werden.

    SELECT ok.name AS Oberkat  
    ,      uk.name AS Unterkat  
      FROM oberkategorie       ok  
      LEFT JOIN unterkategorie uk ON ok.ID = uk.oberkategorieID  
     ORDER BY ok.name ASC -- oder beliebiges anderes Sortierkriterium innerhalb der Oberkategorie  
    ,         uk.name ASC -- oder beliebiges anderes Sortierkriterium innerhalb der Unterkategorie
    

    MfG,
    EKKi

    --
    sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
    1. Ja. Schleifen sind Dir ein Begriff?

      Mehr oder weniger. Warum brauche ich dazu eine Schleife? ich dachte an soetwas:

        
                          <table>  
                           <tr>  
                           <th><b>Menü</b></th>  
                           </tr>  
      <?php  
        $abfrage1 = "SELECT * FROM .... meine abfrage";  
        $ergebnis1 = mysql_query($abfrage1);  
        while($row = mysql_fetch_object($ergebnis1))  
        {  
         		echo "<tr>  
         		      <th>$row->oberkategorie-name</td>  
         		      </tr>  
                            <tr>  
                            <th>$row->unterkategorie-name</td>  
         		      </tr>";		  
        }  
                         </table>  
      ?>
      

      Falsch gedacht? Leider kann ichs nicht testen da ich nicht an meiner eigentlichen umgebung sitze, deshalb vorab die ganze theorie.

      1. Mahlzeit hossi,

        Ja. Schleifen sind Dir ein Begriff?
        Mehr oder weniger. Warum brauche ich dazu eine Schleife? ich dachte an soetwas:

        Preisfrage: was könnte while für ein Sprachkonstrukt sein?

        $abfrage1 = "SELECT * FROM .... meine abfrage";
          $ergebnis1 = mysql_query($abfrage1);
          while($row = mysql_fetch_object($ergebnis1))
          {

        Bis auf die Tatsache, dass die Verwendung von "SELECT *" grundsätzlich mit Kopfüber-an-den-Sackhaaren-aufhängen bestraft werden sollte, meinte ich so etwas in der Art, ja.

        Sinnvollerweise "merkst" Du Dir den Namen der Oberkategorie in einer Variablen, so dass Du ihn nur dann ausgibst, wenn er sich im Vergleich zum vorherigen Datensatz ändert (bzw. am Anfang - aber auch da ändert sich der Inhalt der Variablen ja von "" in z.B. "Foobar").

        MfG,
        EKKi

        --
        sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
        1. moin,

          Bis auf die Tatsache, dass die Verwendung von "SELECT *" grundsätzlich mit Kopfüber-an-den-Sackhaaren-aufhängen bestraft werden sollte

          mal davon abgesehen, dass es grundsätzlich keinen sinn macht, immer grundsätzlich gegen SELECT * zu wettern....

          Ilja

          1. Mahlzeit Ilja,

            Bis auf die Tatsache, dass die Verwendung von "SELECT *" grundsätzlich mit Kopfüber-an-den-Sackhaaren-aufhängen bestraft werden sollte

            mal davon abgesehen, dass es grundsätzlich keinen sinn macht, immer grundsätzlich gegen SELECT * zu wettern....

            Genau. Prinzipien und Allgemeinplätze sind scheiße. Immer.

            ;-)

            Ich halte es bei der Verwendung von "SELECT *" wie bei Berechtigungsvergaben: so wenig wie möglich, so viel wie nötig.

            Insbesondere Anfänger (und als solchen schätze ich hossi mal ein - wenn das nicht stimmt, möge man mir verzeihen) benutzen "SELECT *" viel zu oft viel zu unbedarft ... deswegen kann man ihnen gar nicht oft genug eintrichtern, dass sie möglichst immer darauf verzichten sollten. Sobald ein Entwickler den Status des Anfängers verlassen hat (u.a. weil er weiß, was seine Datenbankabfragen eigentlich genau machen), dann ist es durchaus legitim, bei wenigen notwendigen Ausnahmefällen auch mal "SELECT *" zu nutzen - aber IMHO eben nur bei Leuten, die verstehen, was sie damit anrichten.

            MfG,
            EKKi

            --
            sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
            1. Hi!

              Ich halte es bei der Verwendung von "SELECT *" wie bei Berechtigungsvergaben: so wenig wie möglich, so viel wie nötig.

              Nur dass hier der Vergleich hinkt. "SELECT * nicht verwenden" ist etwas absolutes, "so wenig wie möglich, so viel wie nötig" etwas relatives. Bei der Berechtigungsvergabe kannst du nicht einfach sagen, r-- reicht. Du musst die Besitzverhältnisse berücksichtigen, und wer welche Rechte benötigt. Du entscheidest also individuell/situationsabhängig, welche Rechte zu setzen sind. Und genauso individuell sollte man sich in allen anderen Situationen überlegen, ob das was man da verwendet für das zu erreichende Ziel angemessen ist.

              Insbesondere Anfänger (und als solchen schätze ich hossi mal ein - wenn das nicht stimmt, möge man mir verzeihen) benutzen "SELECT *" viel zu oft viel zu unbedarft ... deswegen kann man ihnen gar nicht oft genug

              ... erklären, in welchen Situationen diese Vorgehensweise Nachteile bringt. Insbesondere sollte man sich selbst Gedanken machen, ob hier eine solche  Situation vorliegen könnte oder ob man einfach nur seine Reflexe testet.

              eintrichtern, dass sie möglichst immer darauf verzichten sollten.

              Nein, nur dann, wenn man nicht alle Spalten braucht. Und dass man auch beim Ergänzen von Spalten so umsichtig agieren sollte, auch die Verwendungsstellen zu prüfen, ob immer noch alle Spalten benötigt werden oder alle außer der neuen.

              Sobald ein Entwickler den Status des Anfängers verlassen hat (u.a. weil er weiß, was seine Datenbankabfragen eigentlich genau machen), dann ist es durchaus legitim, bei wenigen notwendigen Ausnahmefällen auch mal "SELECT *" zu nutzen - aber IMHO eben nur bei Leuten, die verstehen, was sie damit anrichten.

              Und deswegen sollte man ihn mit echtem Wissen und Erfahrungsberichten füttern und nicht mit unerklärten "Grundsätzen".

              Lo!

              1. Hi!

                Sobald ein Entwickler den Status des Anfängers verlassen hat (u.a. weil er weiß, was seine Datenbankabfragen eigentlich genau machen), dann ist es durchaus legitim, bei wenigen notwendigen Ausnahmefällen auch mal "SELECT *" zu nutzen - aber IMHO eben nur bei Leuten, die verstehen, was sie damit anrichten.

                Und deswegen sollte man ihn mit echtem Wissen und Erfahrungsberichten füttern und nicht mit unerklärten "Grundsätzen".

                Statt "deswegen" wollte ich eigentlich sagen "damit er den Status des Anfängers verlassen kann".

                Lo!

              2. ich hätte es nicht besser ausdrücken können, ob man SELECT * einsetzt oder nicht hängt ganz von der jeweiligen situation ab. und das sollte man auch von anfang an so vermitteln.

                Ilja

        2. Hi

          ja, zumindest was php und mysql anbelangt, bin ich blutiger Anfänger!
          Ich kenne nur die Grundzüge, auf was man achten muss usw..

          Aber mit na Schleife schreiben bin ich jetzt erstmal überfordert ..

          Ich konnte mir aber mal mit Hilfe von Tante Google eine Schleife, die fast das macht was ich brauche, ziehen:

          [code=php]
          <?php
          include 'config.php';
          ?>
          <?php
          function build_list($arr) {
            $html = '<ul>';
            foreach ($arr as $id => $val) {
              $html .= '<li>' . htmlspecialchars($val['name']) . ' (' . $id . ')';
              if ($val['children']) {
                $html .= build_list($val['children']);
              }
              $html .= '</li>';
            }
            $html .= '</ul>';
            return $html;
          }

          $sites = array();

          $sql = 'SELECT menu_id, menu_name, parent_id FROM menu';
          $result = $db->query($sql);
          while ($row = $result->fetch_assoc()) {
              $sites[(int)$row['menu_id']] = array(
                  'parent_id' => (int)$row['parent_id'],
                  'name'      => $row['menu_name'],
                  'children'  => array()
              );
          }

          foreach ($sites as $site_id => $site) {
              $sites[$site['parent_id']]['children'][$site_id] =& $sites[$site_id];
          }

          $sites = $sites[0]['children'];

          echo build_list($sites);

          ?>
          [/code=php]

          Die Datenbankstrukur ist hier einfacher gelöst als meine Erste idee :)
          Nur noch eine Tabelle mit
          menu_id    menu_name    parent_id

          Aufbau ist sonst gleich

          Jetzt bekomme ich auf meinem Xampp folgenden Fehler
          Fatal error: Call to a member function query() on a non-object in C:\public\xampp\htdocs\igo\index.php on line 21

          Zeile 21:
          $result = $db->query($sql);

          Das ist eine sql-liste abfrage irgendwie? kann das sein, dass die evtl. nur auf meinem xampp nicht installiert ist?

          Gruß Hossi

  2. Hello,

    ich habe hier gestern schon gepostet zu dem gleichen Thema, mit diesen  Nested-Set-Muster komme ich irgendwie nicht klar bzw. übersteigts meine Fähigkeiten. Mein Ziel ist es, ein Menü mit Baumstruktur auszugeben.

    Nach etwas längerer Überlegung habe ich mir einen neuen Lösungsansatz ausgedacht, der in etwa so aussieht:

    Ich habe eine Datenbank mit 2 Tabellen

    oberkategorie (tabelle1)
    ID       name
    1        Sport
    2        Auto
    3        Essen

    unterkategorie (tabelle2)
    ID       name       oberkategorieID
    1        Fußball     1
    2        Baseball    1
    3        BMW         2
    4        Audi        2
    5        Mercedes    2
    6        Fastfood    3
    7        Vegetarisch 3

    Wie man erkennt, sollen die aus Tabelle2 eingetragenen Werte anhand der oberkategorieID (welche der ID von Tabelle1 entspricht) zugeordnet werden.

    Danach möchte ich die Datensätze mit einem row-> in einer Tabelle ausgeben. Das sollte funktionieren, oder?

    Das ist ein klassischer Gruppenwechsel.
    Da scheiden sich die Geister wieder, ob man eine oder zwei DB-Abfragen durchführen soll, wenn man sowieso eine API (PHP) mit der Darstellung beauftragt.

    In einer Abfrage wäre es ein Join, den Du benötigt, um die Ergebnismenge zu bekommen. Den hat Dir Ekki schon gepostet https://forum.selfhtml.org/?t=198503&m=1333270

    Da er die Ergebnismenge gleich nach Oberkategorie/Unterkategorie hat sortieren lassen, stehen die Ergebnisse bereits in einer brauchbaren Reihenfolge in der Ergebnisliste.
    Diese musst Du nun nur noch mittels einer Schleife abholen und nach der Methode "Gruppenwechsel" (siehe Google) in HTML verpacken.

    Die andere Lösung wäre, erst die Gruppen abzuholen und sich zusammen mit ihrer ID in einem Array zu merken und dann die Detaildatensätze abzuholen.

    Bei der Ausgaben erstezt man dann in der Darstellungs-API die Gruppen-IDs der Detaildatensätze gegen ihre Bedeutungen.

    Diese Vorgehensweise ist immer dann interessant, wenn es sich um größere Datenmengen handelt. Die beiden getrennt geholten Ergebnismengen ergeben i.d.R. zusammen weniger Datenstrom, als wenn Du sie gleich vom DBMS zu einer Ergebnismenge zusammenbauen lässt.

    Es ist dabei aber zu beachten, dass die beiden Einzelabfragen gebunden werden müssen, wenn die Integrität der (abgeholten) Daten wichtig ist.

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Danke, dass sind alles sehr nützliche Tips wenn man sie umsetzen zu weis :(

      Also ich glaub das mit so na Schleife bekomm ich nie gebacken, ich muss mir da ganz was anderes überlegen. Aber danke schon mal :)

      1. Hello,

        Danke, dass sind alles sehr nützliche Tips wenn man sie umsetzen zu weis :(

        Also ich glaub das mit so na Schleife bekomm ich nie gebacken, ich muss mir da ganz was anderes überlegen. Aber danke schon mal :)

        Nicht gleich aufgeben!

        Hast Du es denn überhaupt schon ausprobiert? Zeig mal den Code der Schleife.

        Hast Du bei Google nach "Gruppenwechsel" gesucht? Da landest Du auch bei SelfHTML im  Archiv und im Thread wird alles genau erklärt. Du kannst natürlich auch direkt in unserem Archiv suchen. Hast Du das schon getan?

        Wenn Du es selber möchtest, kommst Du mit SelfHTML immer zu einem Ergebnis. Nur gegen Deinen Willen und ohne Deine Mitarbeit können/wollen wir[1] Dir hier nicht helfen.

        [1] das postuliere ich jetzt einfach mal so, weil es eines der Mottos (?) des Verins ist.

        Ich habe jetzt mal auf PHP umgeschaltet, in der Annahme, dass Du PHP benutzt für die API zur Datenbank.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
      2. Mahlzeit Hossi,

        Danke, dass sind alles sehr nützliche Tips wenn man sie umsetzen zu weis :(

        Die Tipps erfordern halt Grundkenntnisse in der verwendeten Technik. Diese kannst Du Dir im konkreten Fall PHP durch geeignete Tutorials aneignen.

        Also ich glaub das mit so na Schleife bekomm ich nie gebacken, ich muss mir da ganz was anderes überlegen.

        Nein, Du musst nur dafür sorgen, dass Dir die Grundlagen bekannt sind.

        MfG,
        EKKi

        --
        sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|