Внутреннее объединение с count () на три таблицы - PullRequest
20 голосов
/ 29 июня 2010

Простой и быстрый вопрос, у меня есть эти таблицы:

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

Мне нужно запросить список всех людей, подсчитав количество заказов и общее количество элементов, например:

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

Но я не могу заставить его работать! Я пытался

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;

Но это возвращает неверные значения num_*:

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

Я заметил, что если я пытаюсь присоединиться к одной таблице за раз, это работает:

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 |

Как объединить эти два запроса в один?

Ответы [ 6 ]

34 голосов
/ 29 июня 2010

Логичнее объединять товар с заказами, чем с людьми!

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;

Объединение предметов с людьми вызывает много удвоений. Например, изделия из торта в порядке 3 будут связаны с порядком 2 посредством объединения людей, и вы не хотите, чтобы это произошло !!

Итак:

1- Вам нужно хорошее понимание вашей схемы. Предметы - это ссылки на заказы, а не на людей.

2- Вам нужно посчитать отдельные заказы для одного человека, иначе вы будете считать столько же заказов, сколько заказов.

5 голосов
/ 29 июня 2010

Как указал Фрэнк, вам нужно использовать DISTINCT. Кроме того, поскольку вы используете составные первичные ключи (что совершенно нормально, кстати), вам необходимо убедиться, что вы используете весь ключ в своих объединениях:

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

Без I.ord_id = O.ord_id он соединял каждую строку товара с каждой строкой заказа для человека.

3 голосов
/ 02 августа 2013

я пытался поставить разные на обоих, считать (отличный от ord.ord_id) как num_order, считать (различные items.item_id) как num items

работает:)

    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;

Спасибо за тему, это помогает:)

2 голосов
/ 17 августа 2012
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
1 голос
/ 29 июня 2010

Ваше решение почти правильное.Вы можете добавить 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;
0 голосов
/ 15 марта 2014

Нужно понимать, что JOIN или серия JOIN делает с набором данных. С постом strae pe_id = 1, объединенный с соответствующим порядком, а элементы с pe_id = 1 предоставят вам следующие данные для «выбора» из:

[часть участников стола] [часть заказов стола] [часть элементов таблицы]

| 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 | Фу | 1 | 1 | Первый заказ | 1 | 1 | 1 | Apple |
| 1 | Фу | 1 | 1 | Первый заказ | 2 | 1 | 1 | Груша |

Соединения, по сути, дают декартово произведение всех таблиц. По сути, у вас есть этот набор данных для выбора, и поэтому вам нужно различное количество для orders.ord_id и items.item_id. В противном случае оба счета приведут к 2 - потому что у вас фактически есть 2 строки для выбора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...