Marc D: Join über mehrere Tabellen/Suche nach Zuordnungen

Hallo,

ich habe ein kleines Problem mit einer Query, bei der ich Personen mit Eigenschaften suchen möchte. Das ganze läuft mit Postgres 8.3.

Meine Tabellen lauten:

People: id, name

Feature: id, name

Personfeatures: id, person_id, feature_id

Nun möchte ich Personen suchen, die zwei oder mehrere Eigenschaften haben.

Eine Anfrage in der Art:

SELECT p.id, p.name FROM people AS p INNER JOIN personfeatures AS pf ON pf.person_id = p.id WHERE pf.feature_id = 1 AND pf.feature_id = 2

liefert mir ja kein Ergebnis, da es keinen einzelnen Datensatz gibt, der beide ids gleichzeitig hat.

Mir sind nun zwei Lösungen eingefallen:

SELECT p.id, p.name FROM people AS p INNER JOIN personfeatures AS pf ON pf.person_id = p.id WHERE pf.feature_id = 1 OR pf.feature_id = 2 GROUP BY p.id HAVING count(p.id) = 2

oder

SELECT p.id, p.name FROM people AS p INNER JOIN personfeatures AS pf1 ON pf1.person_id = p.id INNER JOIN personfeatures AS pf2 ON pf2.person_id = p.id WHERE pf1.feature_id = 1 AND pf2.feature_id = 2

Gibt es noch eine elegantere Lösung? Wenn nein, welche meiner Lösungen wäre eurer Meinung nach zu bevorzugen.

Vielen Dank für die Hilfe

Marc

  1. Hallo,

    Meine Tabellen lauten:

    People: id, name
    Feature: id, name
    Personfeatures: id, person_id, feature_id

    Nun möchte ich Personen suchen, die zwei oder mehrere Eigenschaften haben.
    Mir sind nun zwei Lösungen eingefallen:

    Gibt es noch eine elegantere Lösung?

    Ja.

    Wenn nein, welche meiner Lösungen wäre eurer Meinung nach zu bevorzugen.

    Sowieso keine von beiden, da ein Selfjoin nicht besonders gut skaliert.

    Freundliche Grüße

    Vinzenz

  2. moin,

    deine abfragen sind beide auch fachlich falsch, zumindestens nach dem was du als anforderung geschrieben hast.

    1.Lösung

    SELECT p.*
    FROM People p
    WHERE (SELECT COUNT(*)
           FROM Personfeature pf
           WHERE pf.person_id = p.id
          ) >= 2
    ;

    2.Lösung

    SELECT p.*
    FROM People p
    WHERE p.id IN (SELECT pf.id
                   FROM Personfeature pf
                   GROUP BY pf.person_id
                   HAVING COUNT(*) > 1
                  )
    ;

    probiere beide aus, schaue welche schneller ausgeführt wird. indexe sollten allerdings auf den fremdschlüsseln liegen, wobei ich auch davon ausgehen, dass ein UNIQUE INDEX auf den spalten person_id und feature_id liegt.

    Ilja