e7: SQL: Bei JOIN mehrere Datensätze zusammenfassen

Hi,

vermutlich steh ich auf dem Schlauch, und mir fehlen einfach die passenden Suchbegriffe...

Und zwar bastel ich zur Zeit an einem kleinen Blog, natürlich mit Tags und so. Folgendes Problem:

Meine erste Idee: eine Tabelle für die Blogeinträge, ein Datensatz pro Eintrag, und dabei ein Feld 'tags', einzeln durch Leerzeichen getrennt. Vorteil: Einfach reinzustopfen und wieder auszulesen, Nachteil wird spätestens der Aufwand bei der Tag-Cloud.

Meine zweite Idee: Tags in eine eigene Tabelle stopfen und das ganze dann wieder zusammen-joinen.

Hier liegt dann auch schon das Problem begraben. Ich hab leider keinen Plan, wie ich das am sinnvollsten wieder abfrage... Also angenommen folgende Struktur:

blog_entry: ENTRY_ID, TITEL, INHALT, SONSTWAS
blog_tags: ID, TAG_ID, ENTRY_ID

Wenn ich das joine, krieg ich nun massig Datensätze raus - für einen Blogeintrag schon so viele Datensätze, wie diesem Tags zugewiesen sind. Was ich möchte: Einen Datensatz pro Blogeintrag, egal wie viele Tags, aber dennoch alle Tags in diesem Datensatz drin.

Ist das nicht möglich, gibt es sinnvollere Varianten, oder wie stell ich das am dümmsten an?

Schon mal Danke für eure Mühe...

e7

  1. Hello,

    Ist das nicht möglich, gibt es sinnvollere Varianten, oder wie stell ich das am dümmsten an?

    unter MySQL gibts da tatsächlich eine schöne dumme Variante: GROUP_CONCAT, dann gruppiert über die Spalten der Blog-Tabelle.

    MfG
    Rouven

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

      super - genau so etwas such ich eigentlich.

      unter MySQL gibts da

      Das hingegen... naja, macht mich grad nicht so glücklich. Klar, das Blog wird vermutlich eh nie was anderes als MySQL zu sehen bekommen. Aber wenn doch - ich hab die Datenbank-Zugriffe gekapselt, um das auch für andere Datenbanken verwendbar zu machen, und hatte das eigentlich auch vor.

      Und scheinbar beschränkt das Teil wegen group_concat_max_len = 1024 die Tags entsprechend...

      Wie macht das ein SQL-Standard-Mensch?

      e7

      1. Hello,

        Wie macht das ein SQL-Standard-Mensch?

        • Skriptlogik
        • Stored Procedure
        • 2 Abfragen

        Ist nicht der SINN einer Datenbankkapselung, dass man in der Datenbank spezifische Anfragen machen kann ohne sich nach außen darum Gedanken machen zu müssen, welche das gerade ist?

        MfG
        Rouven

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

          • Skriptlogik

          Das wäre ziemlich viel Gefrickel und vermutlich nicht gerade effizient, wenn ich sehe, was dann da zwischen Server und Client an überflüssigen Informationen übertragen wird. Also erst im Script ausfiltern wäre doof...

          • 2 Abfragen

          Aus zwei Abfragen werden dann schnell 10, oder alternativ ein ziemliches Durcheinander. Aber mal schauen, vielleicht gibts da ja ne saubere Lösung.

          • Stored Procedure

          Interessantes Thema. Leider fehlt mir aber die Zeit, wegen ein paar Tags mich da erst reinzuarbeiten :(

          Was ich mich frag: Gab es solche Probleme nicht, als der SQL-Standard festgelegt wurde, und man sich so Dinge wie JOIN ausgedacht hatte?

          e7

          1. Hello,

            Was ich mich frag: Gab es solche Probleme nicht, als der SQL-Standard festgelegt wurde, und man sich so Dinge wie JOIN ausgedacht hatte?

            Relationale Datenbanken beruhen im Wesentlichen auf mathematischen Modellen. Kreuzprodukte und damit in einfachster Form auch Joins sind ein Produkt dessen - im wahrsten Sinne des Wortes.
            Du kannst die Frage stellen, warum außer MySQL niemand (oder wenige) ein GROUP_CONCAT anbieten, das finde ich persönlich auch bedauerlich, aber das ist leider so. Du kannst gleiche Elemente gruppieren und aus der Gruppe eines auswählen. Du kannst gleiche Elemente gruppieren und ihre Summe/Durchschnitt berechnen. Aber letzten Endes sind das Zahlenoperationen. Für Texte ist in dem Modell erstmal kein Platz, damit schert GROUP_CONCAT aus der Reihe.

            Ansonsten, mit Scriptlogik meinte ich _nicht_ clientseitig, sondern serverseitig. Und was mehrere Abfragen angeht, es gibt kein Gesetz, dass eine Seite aus einer Abfrage zusammengestellt werden muss. Überleg doch mal, wenn du dir das komponentenorientiert vorstellst, dann hast du eine Komponente, die sich mit der Ausgabe des Blogs befasst, und eine weitere, die sich mit der Ausgabe von Tagclouds befasst. Logischerweise hättest du dann zwei Abfragen und das wäre völlig in Ordnung.

            MfG
            Rouven

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

              Du kannst gleiche Elemente gruppieren und ihre Summe/Durchschnitt berechnen. Aber letzten Endes sind das Zahlenoperationen. Für Texte ist in dem Modell erstmal kein Platz, damit schert GROUP_CONCAT aus der Reihe.

              Aus Programmierersicht (im Gegensatz zur Mathematikersicht) ist eine Funktion, die Texte hintereinander setzt, erst mal auch nur eine Definition mit Code dahinter, wie eine Funktion, die Zahlen addiert. Ein Datenbankmodell hängt in dem Sinne da noch nicht dran, ob SUM() nun zusammenzählt oder hintereinander setzt. Also hätte (ich weiß, hätte...) man - wie mit GROUP_CONCAT geschehen - auch was im Standard drehen können.

              Und was mehrere Abfragen angeht, es gibt kein Gesetz, dass eine Seite aus einer Abfrage zusammengestellt werden muss.

              Ist aber aus Performance-Gründen wünschenswert. Eine Abfrage mit simplen JOINs, die vom DB-Server entsprechend optimiert werden können, wäre der Idealfall.

              Überleg doch mal, wenn du dir das komponentenorientiert vorstellst, dann hast du eine Komponente, die sich mit der Ausgabe des Blogs befasst,

              Ja. Daran arbeite ich im Prinzip.

              und eine weitere, die sich mit der Ausgabe von Tagclouds befasst.

              Daran auch, sobald geklärt ist, wie die Tags gespeichert werden.

              Logischerweise hättest du dann zwei Abfragen und das wäre völlig in Ordnung.

              Hier kommt z. B. die Auflistung mehrerer Blogeinträge auf einer Seite ins Spiel. Für jeden Eintrag (also beispielsweise 10 Einträge pro Seite) noch mal eine Abfrage für die Tags - das macht dann schon 1+10=11 Abfragen. Oder aber einen komplizierten Code, der die IDs der Blogeinträge in eine neue Abfrage wurschtelt, die durchführt, und dann aufpassen muss, dass diese auch wieder korrekt zugeordnet werden.

              Klar wär es kein Problem, mehrere Abfragen zu machen - ich will aber das ganze recht performant halten, d. h. nicht wie diverse Boards, die auf massig Abfragen setzen (irgendwo hatte ich da mal in einem Blog was gelesen, da wurde so ein Teil regelrecht auseinander genommen wegen seinen 50 Abfragen pro Seitenabruf oder so)...

              e7

              1. Hallo

                Ist aber aus Performance-Gründen wünschenswert. Eine Abfrage mit simplen JOINs, die vom DB-Server entsprechend optimiert werden können, wäre der Idealfall.

                Nein, nicht unbedingt. Vergiß nicht Rouvens Bemerkung: Produkt! Die Anzahl der
                zu betrachtenden Datensätze kann schnell ausufern.

                Überleg doch mal, wenn du dir das komponentenorientiert vorstellst, dann hast du eine Komponente, die sich mit der Ausgabe des Blogs befasst,
                und eine weitere, die sich mit der Ausgabe von Tagclouds befasst.

                Daran auch, sobald geklärt ist, wie die Tags gespeichert werden.

                Logischerweise hättest du dann zwei Abfragen und das wäre völlig in Ordnung.

                Hier kommt z. B. die Auflistung mehrerer Blogeinträge auf einer Seite ins Spiel. Für jeden Eintrag (also beispielsweise 10 Einträge pro Seite) noch mal eine Abfrage für die Tags - das macht dann schon 1+10=11 Abfragen.

                Wo ist das Problem? Blogeintrag und Tags haben eine 1:n-Beziehung.
                Und für Deine Tag-Cloud, da benötigst Du normalerweise doch die Häufigkeiten der Tags, tuts ein simples SELECT tag, COUNT(tag) AS anzahl FROM .... Das ist eine einzige Abfrage für die Tag-Cloud. Und davon hat man
                doch nur eine, oder?

                Freundliche Grüße

                Vinzenz

                1. Hi,

                  Nein, nicht unbedingt. Vergiß nicht Rouvens Bemerkung: Produkt! Die Anzahl der
                  zu betrachtenden Datensätze kann schnell ausufern.

                  Das wäre eine seitenweise Ausgabe, also 10 Einträge pro Seite oder halt im Archiv meinetwegen 30 Datensätze (und das wird ja nicht so oft aufgerufen).

                  Und für Deine Tag-Cloud, da benötigst Du normalerweise doch die Häufigkeiten der Tags,

                  Das wär das geringste Problem, die Tag-Cloud kann man Cachen oder sonst was. Es geht mir hauptsächlich um die Übersichtsseite.

                  Die neuesten 10 Einträge (bzw. beliebige Seiten später), die evtl. irgendwie noch die Anzahl der Kommentare mit irgendeinem COUNT() und JOIN rausziehen, und halt die Tags schön brav anzeigen.

                  e7