在三个表上使用count()进行内连接

时间:2010-06-29 14:09:30

标签: sql join count

简单而快速的问题,我有这些表:

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

如何将这两个查询合并为一个?

5 个答案:

答案 0 :(得分:34)

将项目与订单联系起来比使用人员更有意义!

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-您需要为一个人计算不同的订单,否则您将计算与订单一样多的商品。

答案 1 :(得分:5)

正如弗兰克指出的那样,你需要使用DISTINCT。此外,由于您使用的是复合主键(完全没问题,BTW),因此您需要确保在连接中使用整个键:

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,则会将每个项目行连接到一个人的每个订单行。

答案 2 :(得分:3)

我试着把两者分开, count(distinct ord.ord_id)为num_order, 将(distinct 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;

感谢线程帮助:)

答案 3 :(得分:1)

您的解决方案几乎是正确的。你可以添加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;

答案 4 :(得分:0)

需要了解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 | Foo | 1 | 1 |第一顺序| 1 | 1 | 1 | Apple |
  | 1 | Foo | 1 | 1 |第一顺序| 2 | 1 | 1 |梨|

联接基本上是所有表格的笛卡尔积。您基本上可以从中选择数据集,这就是您需要对orders.ord_id和items.item_id进行独特计数的原因。否则两个计数都将产生2 - 因为你实际上有2行可供选择。