SQL Abfrage um die Ecke ;)

  • Hallo zusammen,

    Ich komme gerade nicht auf die Lösung eine Abfrage zu schreiben, die mir das nachfolgende Problem löst.
    Ich habe folgende (auf die Problemstellung vereinfachte) Tabellen, mit einer n-m Beziehung zwischen box und item verknüpft über box_item :

    box

    boxid boxname
    1 box1
    2 box2
    3 box3

    box_item

    boxid itemid
    1 1
    1 2
    2 1
    2 3
    3 1
    3 2


    item

    itemid itemname
    1 item1
    2 item2
    3 item3
    4 item4
    5 item5

    Ich muss jetzt die boxid's jener Boxen bekommen, die eine gegebene Menge von itemid's enthalten.
    Bspw. würde ich erwarten, dass die Abfrage für die itemids {1,3} die boxid {2} zurückgibt.
    Bei der Abfrage für die itemids {1,2} soll das Ergebnis die boxids {1,3} sein.
    Falls nicht alle itemids in einer box enthalten sind, soll eine leere Menge zurückgegeben werden. Bspw. itemids {1,2,3} führt zu boxids {}
    Falls alle itemids in einer box enthalten sind, allerdings noch weitere items in der box sind, so soll auch eine leere Menge zurückgegeben werden. Bspw. itemids {1} führt zu boxids {}.

    Hier meine Startlösung, die leider nicht das gewünschte Ergebnis bringt:

    SQL
    select boxid from box natural join box_item natural join item where itemid = 1 or itemid = 3

    Im Programmcode wird dann später itemid insofern parametrisiert, dass nach beliebig vielen itemids mit benutzerdefinierten Werten gesucht werden kann.

    Wer immer nur das tut, was er bereits kann - wird auch immer nur das bleiben, was er bereits ist!

  • Sowas?:

    SQL
    SELECT boxid AS ID, boxname as Name
    FROM box JOIN box_item USING (boxid) JOIN item USING(itemid)
    WHERE itemid IN (1, 3)
    GROUP BY boxid
    HAVING Count(itemid) = 2;

    Hinter das In kommen in Klammern die möglichen Item-IDs.
    Und das Count ganz unten muss die selbe Anzahl haben wie Elemente in der In-Anweisung.

    Edit: Alternative:

    SQL
    SELECT boxid AS ID, boxname as Name
    FROM box JOIN box_item USING (boxid) JOIN item USING(itemid)
    GROUP BY boxid
    HAVING COUNT(itemid NOT IN (1, 2) OR NULL) = 0 AND COUNT(itemid) = 2

    Hinter das NOT IN kommen die itemids, hinter das Count(itemid) kommt die Anzahl der gesuchten itemids.

    Edit 2: Und noch ne Alternative:

    SQL
    SELECT boxid AS ID, boxname as Name
    FROM box JOIN box_item USING (boxid) JOIN item USING(itemid)
    GROUP BY boxid
    HAVING group_concat(itemid, ",") = "1,2"

    Hier werden die itemids als String eingetragen.
    Eventuell wäre ein Order by innerhalb des group_concat notwendig.
    Dieses wäre in MySQL z.B. möglich in Sqlite hingegen nicht.
    Hier geht es also dann schon langsam um die Frage welches DBMS Verwendung finden soll.