2012-09-20 19 views
7

dire che ho un database che ha la gente, negozi di alimentari, e gli articoli si possono acquistare in negozio, in questo modo:molti-a-molti e molti-a-molti incroci

Stores    People    Foods 
----------------- ------------------ ------------------ 
| id | name | | id | name | | id | name | 
----------------- ------------------ ------------------ 
| 1 | Giant | | 1 | Jon Skeet | | 1 | Tomatoes | 
| 2 | Vons | | 2 | KLee1  | | 2 | Apples | 
| 3 | Safeway | ------------------ | 3 | Potatoes | 
-----------------       ------------------ 

Ho un ulteriore tavolo che tenere traccia di quali negozi vendono ciò:

Inventory 
-------------------- 
| store_id| food_id| 
-------------------- 
| 1  | 1  | 
| 1  | 2  | 
| 2  | 1  | 
| 3  | 1  | 
| 3  | 2  | 
| 3  | 3  | 
-------------------- 

E ho un altro tabella che ha liste della spesa su di esso

Lists 
--------------------- 
| person_id| food_id| 
--------------------- 
| 1  | 1  | 
| 1  | 2  | 
| 1  | 3  | 
| 2  | 1  | 
| 2  | 3  | 
--------------------- 

mio la domanda è, data una persona, o il loro id, qual è il modo migliore per capire a quali negozi possono andare in modo da ottenere tutto nella loro lista. Esiste uno schema per questi tipi di calcoli in MySQL?

Il mio tentativo (molto brutto e disordinato) è qualcosa di simile:

-- Given that _pid is the person_id we want to get the list of stores for. 

SELECT stores.name, store_id, num, COUNT(*) AS counter 
FROM lists 
    INNER JOIN inventory 
     ON (lists.food_id=inventory.food_id) 
    INNER JOIN (SELECT COUNT(*) AS num 
      FROM lists WHERE person_id=_pid 
      GROUP BY person_id) AS T 
    INNER JOIN stores ON (stores.id=store_id) 
WHERE person_id=_pid 
GROUP BY store_id 
HAVING counter >= num; 

Grazie per il vostro tempo!

Modifica SQL Fiddle with Data

+2

Grazie per la pubblicazione della tabella DDL/DML ma sarebbe ancora meglio se è stato creato un modello di lavoro su [SQL violino] (http://sqlfiddle.com/) – Taryn

+1

come tale? http://sqlfiddle.com/#!2/83667/6 – KLee1

+0

Perfetto, grazie! :) – Taryn

risposta

3

Se dovessi risolto il problema, mi unirò i quattro tavoli con il loro collega colonna (specificamente le chiavi esterne) poi una sottoquery sulla clausola HAVING per contare il numero di elementi nella lista per ogni persona. Dare una prova,

SET @personID := 1; 

SELECT c.name 
FROM Inventory a 
     INNER JOIN Foods b 
      ON a.food_id = b.id 
     INNER JOIN Stores c 
      ON a.store_id = c.id 
     INNER JOIN Lists d 
      ON d.food_id = b.id 
WHERE d.person_id = @personID 
GROUP BY c.name 
HAVING COUNT(DISTINCT d.food_id) = 
    (
     SELECT COUNT(*) 
     FROM Lists 
     WHERE person_ID = @personID 
    ) 

SQLFiddle Demo

+0

Dovresti essere in grado di fare tutto il lavoro, selezionando tutte le persone che possono soddisfare le loro liste della spesa come un singolo negozio insieme al nome del negozio dove possono farlo senza aver bisogno della notazione '@ personID'. –

+0

@JonathanLeffler Stavo solo rispondendo all'OP ciò che l'OP vuole "La mia domanda è, data una persona, o il loro id ...". Ad ogni modo, aggiornerò semplicemente la risposta :) Grazie. –

+0

C'è un caso d'angolo qui? Cosa succede se la persona non ha nulla nella loro lista? Possono andare in qualsiasi negozio in quel caso. Sarebbe meglio avere una dichiarazione if per questo caso? – KLee1

1

@JohnWoo: perché distinti?

Un altro ...

SET @pid=2; 

SELECT store_id, name 
FROM inventory 
    JOIN lists ON inventory.food_id=lists.food_id 
    JOIN stores ON store_id=stores.id 
WHERE [email protected] 
GROUP BY store_id 
HAVING COUNT(*)=(
    SELECT COUNT(*) 
    FROM lists 
    WHERE [email protected] 
); 
Problemi correlati