Ankündigung

Einklappen
Keine Ankündigung bisher.

Abfrage/Ausgabe bei m:n Beziehung

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Abfrage/Ausgabe bei m:n Beziehung

    Halli hallo,

    ich habe ein kleines Beziehungsproblem und hoffe, dass mir jemand bei der Ausgabe/Abfrage von Tabellen mit n:m-Beziehung helfen kann.

    Die Tabellen sehen so aus:

    Code:
    CREATE TABLE `nt_notes` (
      `id` int(11) NOT NULL auto_increment,
      `title` varchar(255) collate latin1_german2_ci default NULL,
      `note` text collate latin1_german2_ci,
      `date` int(11) NOT NULL default '0',
      `date_changed` int(11) default NULL,
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci;
    
    CREATE TABLE `nt_tags` (
      `id` int(11) NOT NULL auto_increment,
      `tag` varchar(255) collate latin1_german2_ci NOT NULL,
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci;
    
    CREATE TABLE `nt_tags_notes` (
      `id_notes` int(11) NOT NULL default '0',
      `id_tags` int(11) NOT NULL default '0'
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci;

    nt_notes enthält Notizen, nt_tags enhält Tags zu den Notizen und nt_tags_notes verknüpft die beiden über die IDs.

    Nun möchte ich einfach eine Liste der Notizen ausgeben und zu jeder Notiz die entsprechenden Tags. Momentan frage ich dazu nt_notes ab und in der while-Schleife dann jeweils extra nach den Tags, was natürlich bei größer werdender Datenmenge nicht so performant ist.

    Um alles in einer Abfrage zu bekommen, würde ich es mit folgendem versuchen:
    Code:
    SELECT nt_notes.id,
      nt_notes.title,
      nt_notes.note,
      nt_tags_notes.id_tags,
      nt_tags_notes.id_notes,
      nt_tags.id,
      nt_tags.tag,
      nt_tags_notes.id_notes
    FROM nt_notes, nt_tags_notes, nt_tags
    WHERE (nt_notes.id = nt_tags_notes.id_notes)
      AND (nt_tags.id = nt_tags_notes.id_tags)
    Da fehlen dann aber die notes, die keine passenden Einträge in Tags haben. Vermute, dass ich ein (LEFT) JOIN benötige, habe aber keine Ahnung, wie ich das einsetzen kann.

    Seh ich dass richtig, dass ich die durch mehrere Tags erhaltenen doppelten Zeilen, die sich nur durch die Tas unterscheiden, nur manuell per PHP rausfiltern kann (Gruppenwechsel)?

    Freue mich auf hilfreiche Antworten,
    od

  • #2
    Bei Beziehungsproblemen am besten zur Eheberatung gehen

    Gibt jetzt zwei Möglichkeiten bei dir.

    Entweder genau so wie du es beschrieben hast. Einen LEFT JOIN, somit bekommst du jeden Note (auch die ohne Tag). Allerdings dann eben jede Note auch mehrfach, für jeden Tag eben einmal. Gruppenbruch wäre da dann eine Möglichkeit.

    Besser wäre aber wohl die MySQL Funktion GROUP_CONCAT zu nutzen. Damit kannst du direkt in MySQL alle Tags zusammenbauen.

    Beispiel:
    Code:
    SELECT
      n.id,
      n.title,
      n.note
      GROUPT_CONCAT(t.tag) AS tags
    FROM  nt_notes AS n
    
    LEFT JOIN nt_tags_notes AS nt
    ON        n.id = nt.id_notes
    
    LEFT JOIN nt_tags AS t
    ON        t.id = nt.id_tags
    
    GROUP BY n.id
    Damit bekommst du alle Notes und wenn Tags existieren bekommst du alle Tags in einem String zurück. Ein Beispiel Ergebnis das dann in der Spalte "tags" steht wäre: tag1,tag2,tag3

    Somit hast du pro Note nur noch einen Datensatz, kannst dann mit PHP sehr einfach entscheiden was du mit den Tags machen willst (also entweder direkt so verwenden wenn sie nur ausgegeben werden sollen oder einfach am Komma trennen.

    Kommentar


    • #3
      Na das ist ja schon mal ne chice Antwort.
      Ich bekomm ich aber leider nen fehler:

      #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 '( t.tag ) AS tags FROM nt_notes AS n LEFT JOIN nt_tags_notes AS nt ON n.id =' at line 1


      Wenn ich die Zeile mit dem GROUPT_CONCAT(t.tag) AS tags weglasse wird die Abfrage ausgeführt, jedoch natürlich ohne die Tags auszugeben.

      Die Abfrage mit dem Gruppenbruch würde mich eigentlich generell auch interessieren, falls ich die Tabelle mit den Tags noch um weitere Felder erweitere.

      Hab mal ein wenig experimentiert ob ich ohne das concat was sinnvolles erhalte:
      wenn ich im select nt_tags.tags oder t.tags mit gibt es nen Syntaxfehler. Wenn ich * nehme, dann nicht, anscheinend werden durch das GROUP BY n.id einige Zeilen weggelassen, ohne sieht die Ausgabe schon ganz brauchbar aus. also
      Code:
      SELECT
      *
      FROM  nt_notes AS n
      
      LEFT JOIN nt_tags_notes AS nt
      ON        n.id = nt.id_notes
      
      LEFT JOIN nt_tags AS t
      ON        t.id = nt.id_tags
      Wie sortier ich das nun z.B. nach Datum? Wo müsste das ORDER BY hin, so dass die Zeilen mit den Tags zu ner Note immer noch aufeinander folgen? Würde dann das auseinanderklamüsern per PHP machen.

      Kommentar


      • #4
        die alias bezeichnungen bei tabellen macht man ohne AS einfach nur tabellenname aliasname
        apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

        Kommentar


        • #5
          Hallo,

          statt der Selektion in while() kannst du die Tags auch dabei sammeln und diese später gesammelt abfragen und zuordnen. Das kostet dich zwar mehr Schleifen in PHP, aber du vermeidest damit Queries innerhalb von Schleifen, was eben teilweise sehr stark an die Performanz gehen kann.

          In drei Abfragen kannst du damit alle Werte und Zuordnungen erhalten.

          1. Notes sammeln (SELECT * FROM nt_notes)
          2. diese Notes in der Zuordnungstabelle selektieren, Tags selektieren (SELECT notes_id, tags_id FROM notes_with_tags WHERE notes_id IN ($noteIds))
          3. Tags herausfischen und per Query aus der Datenbank ziehen (SELECT * FROM nt_tags WHERE id IN ($tagIds))
          4. Zuordnung herstellen, die durch Punkt 2 bekannt ist (PHP-seitig)
          "[URL="http://www.youtube.com/watch?v=yMAa_t9k2VA&feature=youtu.be&t=25s"]Mein Name ist Lohse, ich kaufe hier ein.[/URL]"

          Kommentar


          • #6
            Zitat von BlackScorp Beitrag anzeigen
            die alias bezeichnungen bei tabellen macht man ohne AS einfach nur tabellenname aliasname
            Muss nicht bei MySQL, kann auch mit AS gemacht werden.

            Kommentar


            • #7
              Zitat von Flor1an Beitrag anzeigen
              Muss nicht bei MySQL, kann auch mit AS gemacht werden.
              ach kommt von wenn man ständig mit oracle arbeitet
              apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

              Kommentar

              Lädt...
              X