web-dev-qa-db-ger.com

Inner Join mit count () auf drei Tabellen

Einfache und schnelle Frage, ich habe diese 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 muss eine Abfrage haben, in der alle Personen aufgeführt sind, die Anzahl der Bestellungen und die Anzahl der total - Elemente wie folgt:

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

Aber ich kann es nicht zum Laufen bringen! Ich habe es versucht 

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;

Dies gibt jedoch die num_*-Werte falsch zurück:

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

Ich habe bemerkt, dass es funktioniert, wenn ich versuche, mich zu einem Zeitpunkt einer Tabelle anzuschließen:

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 kombiniere ich diese beiden Abfragen in einer?

18
Strae

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

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;

Das Zusammenfügen der Gegenstände mit den Menschen provoziert viele Dublonen. Zum Beispiel werden die Kuchenstücke in Auftrag 3 mit dem Auftrag 2 über den Join zwischen den Leuten verknüpft, und Sie möchten nicht, dass dies geschieht !!

So :

1- Sie benötigen ein gutes Verständnis Ihres Schemas. Artikel sind Links zu Bestellungen und nicht zu Personen. 

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

32
Cyril Gandon

Wie Frank darauf hingewiesen hat, müssen Sie DISTINCT verwenden. Da Sie zusammengesetzte Primärschlüssel verwenden (was vollkommen in Ordnung ist), müssen Sie auch sicherstellen, dass Sie den gesamten Schlüssel in Ihren Joins verwenden:

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 jede Artikelzeile mit jeder Bestellzeile einer Person verbunden.

5
Tom H

ich habe versucht, für beide, count (distinkte ord.ord_id) als num_order, count (distinkte Elemente.item_id) als num-Elemente zu setzen

es funktioniert :)

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

3
Marjunne Romero
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
2
Kamal Deepak

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

Man muss verstehen, was ein JOIN oder eine Reihe von JOINs mit einem Datensatz macht. Mit dem Beitrag von strae erhalten Sie mit einer pe_id von 1, die mit der entsprechenden Reihenfolge und den Elementen in pe_id = 1 verknüpft ist, folgende Daten, aus denen Sie auswählen können:

[Tabelle Personen Teil] [Tabelle Bestellungen Teil] [Tabelle Artikel Teil]

| 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 | Erster Auftrag | 1 | 1 | 1 | Apple |
| 1 | Foo | 1 | 1 | Erster Auftrag | 2 | 1 | 1 | Birne |

Die Verbindungen haben im Wesentlichen ein kartesisches Produkt aller Tische. Im Grunde haben Sie diesen Datensatz zur Auswahl, weshalb Sie eine eindeutige Zählung für orders.ord_id und items.item_id benötigen. Andernfalls führen beide Zählungen zu 2 - weil Sie tatsächlich zwei Zeilen zur Auswahl haben.

0
Alamgir Mand