2012-09-20 41 views
7

Decir que tengo una base de datos que tiene la gente, tiendas de comestibles, y artículos que se pueden comprar en la tienda, así:muchos-a-muchos y muchos-a-muchos intersecciones

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 | 
-----------------       ------------------ 

tengo un adicional mesa que perder de vista que las tiendas venden lo que:

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

Y tengo otra tabla que tiene listas de la compra en ella

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

Mi La pregunta es, dada una persona, o su identificación, cuál es la mejor manera de descubrir a qué tiendas pueden ir para que obtengan todo en su lista. ¿Hay algún patrón para este tipo de cálculos en MySQL?

Mi intento (muy feo y sucio) es algo así como:

-- 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; 

Gracias por su tiempo!

Editar SQL Fiddle with Data

+2

gracias por publicar la mesa DDL/DML pero sería aún mejor si ha creado un modelo de trabajo en [SQL violín] (http://sqlfiddle.com/) – Taryn

+1

¿Me gusta? http://sqlfiddle.com/#!2/83667/6 – KLee1

+0

Perfecto, gracias! :) – Taryn

Respuesta

3

Si tuviera que resuelve el problema, me uniré a las cuatro mesas con su vinculación columna (específicamente las claves externas) y luego una subconsulta en la cláusula HAVING para contar el número de elementos en la lista para cada persona. Dar a este un intento,

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

Debería poder hacer todo el trabajo, seleccionando a todas las personas que pueden satisfacer sus listas de compras como una sola tienda junto con el nombre de la tienda donde pueden hacerlo sin necesitar la notación '@ personID'. –

+0

@JonathanLeffler Estaba respondiendo al OP lo que el OP quiere 'Mi pregunta es, dada una persona, o su identificación ...'. De todos modos, solo actualizaré la respuesta :) Gracias. –

+0

¿Hay un caso de esquina aquí? ¿Qué pasa si la persona no tiene nada en su lista? Pueden ir a cualquier tienda en ese caso. ¿Sería mejor tener una declaración if para este caso? – KLee1

1

@JohnWoo: ¿por qué DISTINCT?

Otro ...

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] 
); 
Cuestiones relacionadas