Markus Möller: (SQL) Verwandte Themen finden

Hallo zusammen,

ich habe folgendes Problem. Eine Tabelle enthält Themen, die 10 Tags besitzen. In etwa so (stark gekürzt).

CREATE tbl_topics (
   id INT,
   title VARCHAR(255),
   tag1 VARCHAR(255),
   tag2 VARCHAR(255),
   tag3 VARCHAR(255)
)

Wie finde ich nun zu einen Thema alle andere Themen, die mindestens zwei gemeinsame Tags besitzen? Die Tags sind nicht sortiert und können auch NULL sein.

Erster Ansatz:
Per PHP alle Tags des Themas zu einem kommaseparierten String zusammenbauen und verwandte Themen dann so suchen:

SELECT * FROM tbl_topics WHERE tag1 IN ($tags) OR tag2 IN ($tags) OR tag3 IN ($tags)

Das funktioniert super, wenn eine Übereinstimmung nötig ist. Ich möchte ein Thema aber nur als verwandt anzeigen, wenn mind. 2 Tags übereinstimmen. Später vielleicht erst ab 4, 5, ...

Die Lösung sollte also auch leicht erweiterbar sein und natürlich recht performant sein.

Ich bin mir sicher, dass es eine einfache Lösung mit count, join, having etc. gibt, stehe aber total auf dem Schlauch. Wer kann helfen?

  1. Hi,

    ich habe folgendes Problem. Eine Tabelle enthält Themen, die 10 Tags besitzen. In etwa so (stark gekürzt).

    CREATE tbl_topics (
       id INT,
       title VARCHAR(255),
       tag1 VARCHAR(255),
       tag2 VARCHAR(255),
       tag3 VARCHAR(255)
    )

    Du hast also ein Problem mit deiner Datenstruktur.
    Also ändere diese.

    Sinnvoll wäre eine weitere Tabelle mit der Zuordnung topic-id:tag-id.

    Per PHP alle Tags des Themas zu einem kommaseparierten String zusammenbauen

    Grottig.
    Schon an einem solchen Punkt sollte einem auffallen, dass das Datenmodell Murks ist.

    Die Lösung sollte also auch leicht erweiterbar sein und natürlich recht performant sein.

    Ein Grund mehr, die Datenstruktur anzupassen.

    MfG ChrisB

    --
    Light travels faster than sound - that's why most people appear bright until you hear them speak.
    1. Hello,

      ich habe folgendes Problem. Eine Tabelle enthält Themen, die 10 Tags besitzen. In etwa so (stark gekürzt).

      CREATE tbl_topics (
          id INT,
          title VARCHAR(255),
          tag1 VARCHAR(255),
          tag2 VARCHAR(255),
          tag3 VARCHAR(255)
      )

      Du hast also ein Problem mit deiner Datenstruktur.
      Also ändere diese.

      Sinnvoll wäre eine weitere Tabelle mit der Zuordnung topic-id:tag-id.

      und bitte bis zu Ende denken:

      Die Themen müssen formalisiert werden, damit man sie wiederfinden kann.
      Dadurch läuft das Ganze auf eine Kreuztabellenabfrage hinaus.

      also
            topics -> inhalt -> themen
               n       n:m        m

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. n'abend,

        Die Themen müssen formalisiert werden, damit man sie wiederfinden kann.
        Dadurch läuft das Ganze auf eine Kreuztabellenabfrage hinaus.

        Du sprichst vermutlich von _N_ormalisieren. Und ja, du hast recht.

        Neben dem Offensichtlichen (Redundanz verhindern) hat die Normalisierung hier aber noch andere Vorteile. Unsere M:N Tabelle besteht aus zwei Fremdschlüsseln, beides Zahlen. Das bedeutet, dass ich nicht ständig "Buchstabe für Buchstabe" miteinander vergleichen muss. Zahlen haben eine feste länge (INT sind 4 Byte). VARCHAR ist, wie der Name schon vermuten lässt, in seiner Größe variabel. Es bedarf nicht viel Hintergrundwissen, um sich zusammenreimen zu können, dass ich schneller Arbeiten kann, wenn ich weiß wo etwas beginnt und endet, als wenn ich erst noch schauen muss wo das Ende sein könnte.

        weiterhin schönen abend...

        --
        #selfhtml hat ein Forum?
        sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
        1. Hello,

          Die Themen müssen formalisiert werden, damit man sie wiederfinden kann.
          Dadurch läuft das Ganze auf eine Kreuztabellenabfrage hinaus.

          Du sprichst vermutlich von _N_ormalisieren. Und ja, du hast recht.

          Stimmt auch.

          Vor dem Normalisieren kommt das Formalisieren, also nur bestimmte Einträge zuzulassen.

          Das Normalisieren bezieht sich dann auf das Zusammenspiel der Daten im System.
          Aber formalsiert können die Daten auch bereits in einer Tabelle sein. Ist dann nur interessant, wie man die Disziplin dafür herstellt.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
      2. Hallo,

        » > ich habe folgendes Problem. Eine Tabelle enthält Themen, die 10 Tags besitzen. In etwa so (stark gekürzt).
        » >
        » > CREATE tbl_topics (
        » >    id INT,
        » >    title VARCHAR(255),
        » >    tag1 VARCHAR(255),
        » >    tag2 VARCHAR(255),
        » >    tag3 VARCHAR(255)
        » > )

        » Sinnvoll wäre eine weitere Tabelle mit der Zuordnung topic-id:tag-id.

        und bitte bis zu Ende denken:

        Die Themen müssen formalisiert werden, damit man sie wiederfinden kann.
        Dadurch läuft das Ganze auf eine Kreuztabellenabfrage hinaus.

        und bitte bis zu Ende denken:

        MySQL bietet keine eingebaute Unterstützung für Kreuztabellenabfragen - vielleicht ist aber MS Access im Einsatz oder eine aktuelle Version des MS SQL Servers, bei deren SQL-Dialekte (Jet-SQL bzw. Transact-SQL) di Unterstützung enthalten ist.

        Ansätze, wie man dieses Problem angehen kann, wenn man es angehen will oder muss, findet man im Archiv.

        Freundliche Grüße

        Vinzenz