unir tablas tabla relacionadas misma inner distintas consultas consultar consulta columnas sql join count

sql - relacionadas - Unión interna con cuenta() en tres tablas



unir dos consultas sql misma tabla (6)

Pregunta simple y rápida, tengo esas tablas:

//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 que incluya a todas las personas, contando el número de pedidos y el número total de artículos, así:

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

Pero no puedo hacerlo funcionar! Lo intenté

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 los valores num_* incorrectos:

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

Noté que si trato de unirme a una mesa a la vez, 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?


¡Tiene más sentido unir el artículo con las órdenes que con la gente!

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;

Unir los elementos con la gente provoca muchos doblones. Por ejemplo, los elementos de la torta en el orden 3 se vincularán con el orden 2 a través de la unión entre las personas, ¡y no querrás que esto suceda!

Asi que :

1- Necesitas una buena comprensión de tu esquema. Los artículos están vinculados a pedidos, y no a personas.

2- Necesita contar órdenes distintas para una persona, de lo contrario contará tantos artículos como órdenes.


Como Frank señaló, necesitas usar DISTINCT. Además, dado que está utilizando claves primarias compuestas (lo que es perfectamente correcto, por cierto), debe asegurarse de que utiliza la clave completa en sus 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 artículo a cada fila de orden para una persona.


Intenté poner distinto en ambos, count (distinto ord.ord_id) como num_order, count (distinto items.item_id) como num items

esta funcionando :)

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


Su solución es casi correcta. Usted podría añadir DISTINCT:

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;


Uno tiene que entender lo que hace un JOIN o una serie de JOIN a un conjunto de datos. Con la publicación de strae, un pe_id de 1 unido con el orden correspondiente y los elementos en pe_id = 1 le dará los siguientes datos para "seleccionar" de:

[porción de personas de la mesa] [porción de órdenes de la mesa] [porción de los elementos de la tabla]

| 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 | Manzana |
| 1 | Foo | 1 | 1 | Primer orden | 2 | 1 | 1 | Pera

Las uniones esencialmente vienen con un producto cartesiano de todas las tablas. Básicamente tienes ese conjunto de datos para seleccionar y es por eso que necesitas un conteo distinto en orders.ord_id y items.item_id. De lo contrario, ambos conteos darán como resultado 2, ya que efectivamente tiene 2 filas para seleccionar.


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