2010-06-29 15 views
16

simple y pregunta rápida, tengo esas tablas:combinación interna con count() en tres mesas

//table people 
| pe_id | pe_name | 
| 1 | Foo | 
| 2 | Bar | 
//orders table 
| ord_id | pe_id | ord_title | 
| 1 | 1 | First order | 
| 2 | 2 | Order two | 
| 3 | 2 | Third order | 
//items table 
| item_id | ord_id | pe_id | title | 
| 1  | 1 | 1 | Apple | 
| 2  | 1 | 1 | Pear | 
| 3  | 2 | 2 | Apple | 
| 4  | 3 | 2 | Orange | 
| 5  | 3 | 2 | Coke | 
| 6  | 3 | 2 | Cake | 

Necesito tener una consulta una lista de todas las personas, contando el número de órdenes y la total de número de artículos, como que:

| pe_name | num_orders | num_items | 
| Foo | 1  | 2  | 
| Bar | 2  | 4  | 

Pero no puedo hacer que funcione! Probé

SELECT 
    people.pe_name, 
    COUNT(orders.ord_id) AS num_orders, 
    COUNT(items.item_id) AS num_items 
FROM 
    people 
    INNER JOIN orders ON (orders.pe_id = people.pe_id) 
    INNER JOIN items ON items.pe_id = people.pe_id 
GROUP BY 
    people.pe_id; 

Pero esto devuelve el num_* valores incorrectos:

| name | num_orders | num_items | 
| Foo | 2  | 2  | 
| Bar | 8  | 8  | 

me di cuenta de que si trato de unirse a una mesa al mismo tiempo, funciona:

SELECT 
    people.pe_name, 
    COUNT(orders.ord_id) AS num_orders 
FROM 
    people 
    INNER JOIN orders ON (orders.pe_id = people.pe_id) 
GROUP BY 
    people.pe_id; 

//give me: 
| pe_name | num_orders | 
| Foo  |   1 | 
| Bar  |   2 | 

//and: 
SELECT 
    people.pe_name, 
    COUNT(items.item_id) AS num_items 
FROM 
    people 
    INNER JOIN items ON (items.pe_id = people.pe_id) 
GROUP BY 
    people.pe_id; 
//output: 
| pe_name | num_items | 
| Foo  |   2 | 
| Bar  |   4 | 

Cómo combinar esas dos consultas en una?

+1

Sus tablas realmente necesitan reorganizarse. La tabla de artículos no debe hacer referencia a la tabla de pedidos y, desde luego, no a la tabla de personas, y necesita una nueva tabla para una relación de varios a muchos, como pedidos y artículos. –

+0

¿Por qué necesitaría un número de muchos a muchos si un pedido solo puede pertenecer a una persona? Su modelo tiene perfecto sentido. –

+0

@adam: no entiendo su sugerencia. Entonces, solo el ID inútil que veo es el pe_id en la tabla de elementos, pero tal vez podría ser útil en el futuro para obtener el total de elementos de un pueblo sin unirse a la tabla de pedidos. ¿Qué quiere decir con "La tabla de artículos no debe hacer referencia al pedido"? – Strae

Respuesta

27

Es más sentido para unirse al elemento con las órdenes que a las personas!

SELECT 
    people.pe_name, 
    COUNT(distinct orders.ord_id) AS num_orders, 
    COUNT(items.item_id) AS num_items 
FROM 
    people 
    INNER JOIN orders ON orders.pe_id = people.pe_id 
     INNER JOIN items ON items.ord_id = orders.ord_id 
GROUP BY 
    people.pe_id; 

Ingreso los artículos con las personas provocan una gran cantidad de doublons. Por ejemplo, los artículos de tarta en orden 3 se vincularán con la orden 2 a través de la unión entre las personas, ¡y usted no quiere que esto suceda!

Así:

1- Se necesita una buena comprensión de su esquema. Los artículos son enlaces a pedidos y no a personas.

2- Necesita contar distintos pedidos para una sola persona, de lo contrario contará tantos elementos como pedidos.

+0

Tiene más sentido, pero con el esquema actual, no hará la diferencia. –

+0

"Los elementos son enlaces a pedidos, y no a personas" .. de acuerdo, pero el pe_id en la tabla de elementos me permite, por ejemplo, recuperar todos los elementos para 1 personas sin unirse a la tabla de pedidos .. puede ser útil, tal vez, y si no, puedo eliminar fácilmente el índice en el paso de optimización final;) ​​ – Strae

+0

no elimine el pe_id de la tabla de elementos, podría ser un buen atajo para algunas consultas. PERO para este en particular, ¡simplemente no es útil! –

1

Su solución es casi correcta. Se podría añadir distintas:

SELECT 
    people.pe_name, 
    COUNT(distinct orders.ord_id) AS num_orders, 
    COUNT(items.item_id) AS num_items 
FROM 
    people 
    INNER JOIN orders ON (orders.pe_id = people.pe_id) 
    INNER JOIN items ON items.pe_id = people.pe_id 
GROUP BY 
    people.pe_id; 
+0

No da los buenos resultados. | nombre | num_orders | num_items | | Foo | 1 | 2 | | Bar | 2 | 8 | –

+0

Sí, esto da la cuenta de elementos rusos, debe agregar la cláusula 'distinct' en el recuento (elementos) también y luego funciona – Strae

4

Como señaló Frank, debe utilizar DISTINCT. Además, dado que está utilizando claves primarias compuestas (que está perfectamente bien, por cierto) que necesita para asegurarse de que se utiliza la llave entera en su Combinaciones:

SELECT 
    P.pe_name, 
    COUNT(DISTINCT O.ord_id) AS num_orders, 
    COUNT(I.item_id) AS num_items 
FROM 
    People P 
INNER JOIN Orders O ON 
    O.pe_id = P.pe_id 
INNER JOIN Items I ON 
    I.ord_id = O.ord_id AND 
    I.pe_id = O.pe_id 
GROUP BY 
    P.pe_name 

Sin I.ord_id = O.ord_id se unía cada fila de elementos a cada fila de órdenes para una persona.

1
select pe_name,count(distinct b.ord_id),count(c.item_id) 
from people a, order1 as b ,item as c 
where a.pe_id=b.pe_id and 
b.ord_id=c.order_id group by a.pe_id,pe_name 
+0

Gracias por la actualización Bo Persson –

3

He intentado poner distinta en ambos, recuento (ord.ord_id distinta) como num_order, recuento (items.item_id distinta) como elementos num

su trabajo :)

SELECT 
     people.pe_name, 
     COUNT(distinct orders.ord_id) AS num_orders, 
     COUNT(distinct items.item_id) AS num_items 
    FROM 
     people 
     INNER JOIN orders ON (orders.pe_id = people.pe_id) 
     INNER JOIN items ON items.pe_id = people.pe_id 
    GROUP BY 
     people.pe_id; 

Gracias por el hilo que ayuda :)

0

uno tiene que entender lo que una unión o una serie de combinaciones hace a un conjunto de datos.Con el post de strae, un pe_id de 1 unió con orden y elementos correspondientes en pe_id = 1 le dará los siguientes datos para "seleccionar" a partir de:

[porciones personas de mesa] [órdenes de mesa porción] [artículos de mesa porción ]

| people.pe_id | people.pe_name | orders.ord_id | orders.pe_id | orders.ord_title | item.item_id | item.ord_id | item.pe_id | item.title |

| 1 | Foo | 1 | 1 | Primer orden | 1 | 1 | 1 | Apple |
| 1 | Foo | 1 | 1 | Primer orden | 2 | 1 | 1 | Pera |

Las uniones esencialmente se presentan con un producto cartesiano de todas las tablas. Básicamente tiene ese conjunto de datos para seleccionar y es por eso que necesita un recuento distinto en orders.ord_id y items.item_id. De lo contrario, ambos recuentos resultarán en 2, ya que efectivamente tiene 2 filas para seleccionar.

Cuestiones relacionadas