2010-06-29 18 views
16

Einfache und schnelle Frage, ich habe diese Tabellen:Inner Join mit count() auf drei Tabellen

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

Ich brauche eine Abfrage haben alle Menschen die Auflistung, zählen die Anzahl der Aufträge und die Gesamt Anzahl der Artikel, wie diese:

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

Aber ich kann es nicht funktionieren lassen! Ich versuchte

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; 

Aber dies gibt die num_* Werte falsch:

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

Ich habe bemerkt, dass, wenn ich versuche, eine Tabelle zur Zeit zu verbinden, funktioniert es:

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 | 

Wie Kombinieren Sie diese beiden Abfragen in einem?

+1

Ihre Tabellen müssen wirklich neu organisiert werden. Die Artikeltabelle sollte nicht auf die Auftragstabelle und schon gar nicht auf die Personentabelle verweisen, und Sie benötigen eine neue Tabelle für eine Viele-zu-Viele-Beziehung wie Aufträge und Artikel. –

+0

Warum sollte er ein Viele-zu-Viele brauchen, wenn eine Bestellung nur einer Person gehören kann? Sein Modell macht durchaus Sinn. –

+0

@adam: Ich verstehe Ihren Vorschlag nicht. Dann ist nur die nutzlose ID, die ich sehe, die pe_id in der Items-Tabelle, aber vielleicht könnte sie in Zukunft nützlich sein, um die gesamten Items eines People zu erhalten, ohne der Order-Tabelle beizutreten. Was meinen Sie mit "Die Artikeltabelle sollte nicht auf die Bestellung verweisen"? – Strae

Antwort

27

Es ist sinnvoller, den Artikel mit den Bestellungen als den Menschen zu verbinden!

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; 

Verbinden Sie die Elemente mit den Menschen provozieren viele Doublons. Zum Beispiel werden die Kuchen Artikel in der Reihenfolge 3 mit der Bestellung 2 über die Verbindung zwischen den Menschen verknüpft werden, und Sie wollen nicht, dass dies geschieht !!

So:

1- Sie müssen ein gutes Verständnis für Ihr Schema. Elemente sind Verknüpfungen zu Bestellungen und nicht zu Personen.

2- Sie müssen bestimmte Bestellungen für eine Person zählen, sonst zählen Sie so viele Artikel wie Bestellungen.

+0

Es macht mehr Sinn, aber mit dem aktuellen Schema wird es keinen Unterschied machen. –

+0

"Artikel sind Link zu Bestellungen und nicht zu Personen" .. zustimmen, aber die Pe_id auf der Artikeltabelle lassen Sie mich, zum Beispiel, alle Artikel für 1 Personen abrufen, ohne die Bestellungen Tabelle beigetreten .. kann nützlich sein, vielleicht, und wenn nicht, kann ich den Index im letzten Optimierungsschritt leicht entfernen;) – Strae

+0

nicht die Pe_id der Items-Tabelle entfernen, könnte es eine gute Abkürzung für einige Abfrage sein. ABER für diesen besonderen, es ist einfach nicht nützlich! –

1

Ihre Lösung ist nahezu korrekt. Sie könnten DISTINCT hinzufügen:

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

Gibt nicht die guten Ergebnisse. | Name | num_orders | num_items | | Foo | 1 | 2 | | Bar | 2 | 8 | –

+0

Ja, dies gibt die Anzahl der rong Elemente, Sie sollten auch die 'distinct' Klausel in der Anzahl (Elemente) hinzufügen und dann funktioniert – Strae

4

Wie Frank darauf hingewiesen hat, müssen Sie DISTINCT verwenden. Auch da Sie Composite Primärschlüssel verwenden (was völlig in Ordnung ist, BTW) müssen Sie sicherstellen, dass Sie den gesamten Schlüssel verwenden in Ihrem verbindet:

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 

Ohne I.ord_id = O.ord_id wurde Beitritt Jede Artikelzeile zu jeder Bestellzeile für eine Person.

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

Danke für das Update Bo Persson –

3

Ich habe versucht, auf beide verschieden setzen, count (distinct ord.ord_id) als num_order, count (distinct items.item_id) als num Artikel

seine Arbeits :)

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; 

Danke für den Thread, den es hilft :)

0

Man muss verstehen, was ein JOIN oder eine Reihe von JOINs mit einer Reihe von Daten tut.Mit strae der Post, trat ein pe_id von 1 mit entsprechenden Reihenfolge und Elemente auf pe_id = 1 geben Sie die folgenden Daten zu „wählen“ aus:

[table Menschen Teil] [Tabelle Aufträge Abschnitt] [Tabelle Artikel Abschnitt ]

| 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 | Erste Bestellung | 1 | 1 | 1 | Apfel |
| 1 | Foo | 1 | 1 | Erste Bestellung | 2 | 1 | 1 | Birne |

Die Joins kommen im Wesentlichen mit einem kartesischen Produkt aller Tabellen. Sie haben im Grunde diesen Datensatz zur Auswahl und deshalb brauchen Sie eine eindeutige Anzahl für orders.ord_id und items.item_id. Andernfalls ergeben beide Zählungen 2 - weil Sie effektiv 2 Zeilen zur Auswahl haben.