Question simple et rapide, j'ai ces tableaux:
//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 |
Il me faut une requête répertoriant toutes les personnes, en comptant le nombre de commandes et le total nombre d'éléments, comme celui-ci:
| pe_name | num_orders | num_items |
| Foo | 1 | 2 |
| Bar | 2 | 4 |
Mais je ne peux pas le faire fonctionner! J'ai essayé
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;
Mais cela retourne les valeurs num_*
incorrectes:
| name | num_orders | num_items |
| Foo | 2 | 2 |
| Bar | 8 | 8 |
J'ai remarqué que si j'essaie de joindre une table à la fois, cela fonctionne:
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 |
Comment combiner ces deux requêtes en une?
Il est plus logique de joindre le produit aux commandes qu'aux personnes!
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;
Joindre les objets aux gens provoque beaucoup de doublons. Par exemple, les gâteaux de l’ordre 3 seront liés à l’ordre 2 via la jonction entre les personnes et vous ne voulez pas que cela se produise!
Alors :
1- Vous avez besoin d'une bonne compréhension de votre schéma. Les articles sont liés aux commandes et non aux personnes.
2- Vous devez compter les commandes distinctes pour une personne, sinon vous compterez autant d'articles que de commandes.
Comme Frank l'a souligné, vous devez utiliser DISTINCT. De plus, puisque vous utilisez des clés primaires composites (ce qui est parfaitement, BTW), vous devez vous assurer que vous utilisez la clé entière dans vos jointures:
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
Sans I.ord_id = O.ord_id, il reliait chaque ligne d'élément à chaque ligne d'ordre d'une personne.
j'ai essayé de mettre distinct sur les deux, count (distinct ord.ord_id) comme num_order, count (distinct items.item_id) comme éléments de num
ça marche :)
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;
Merci pour le fil ça aide :)
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
Votre solution est presque correcte. Vous pouvez ajouter 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;
Il faut comprendre ce qu’un joint ou une série de joints fait à un ensemble de données. Avec le message de strae, un pe_id de 1 rejoint la commande correspondante et les éléments sur pe_id = 1 vous donneront les données suivantes pour "sélectionner" parmi:
[partie personnes de la table] [partie commandes de la table] [partie éléments de la table]
| 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 | Première commande | 1 | 1 | 1 | Apple |
| 1 | Foo | 1 | 1 | Première commande | 2 | 1 | 1 | Poire |
Les jointures proposent essentiellement un produit cartésien de toutes les tables. Vous avez essentiellement le choix de cet ensemble de données et c'est pourquoi vous avez besoin d'un décompte distinct pour orders.ord_id et items.item_id. Sinon, les deux comptages donneront 2 - car vous avez effectivement 2 lignes à sélectionner.