MYSQL计算多个表的匹配结果

时间:2014-05-21 10:47:40

标签: mysql sql count

我有以下表格

商业

    +-------------+--------------+------+-----+---------+----------------+
    | Field       | Type         | Null | Key | Default | Extra          |
    +-------------+--------------+------+-----+---------+----------------+
    | b_id        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
    | b_name      | varchar(255) | NO   |     | NULL    |                |
    +-------------+--------------+------+-----+---------+----------------+

位置

    +-------------+--------------+------+-----+---------+----------------+
    | Field       | Type         | Null | Key | Default | Extra          |
    +-------------+--------------+------+-----+---------+----------------+
    | l_id        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
    | l_name      | varchar(255) | NO   |     | NULL    |                |
    | b_id        | big(20)      | NO   |     | NULL    |                |
    +-------------+--------------+------+-----+---------+----------------+

工作

    +-------------+--------------+------+-----+---------+----------------+
    | Field       | Type         | Null | Key | Default | Extra          |
    +-------------+--------------+------+-----+---------+----------------+
    | j_id        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
    | j_name      | varchar(255) | NO   |     | NULL    |                |
    | b_id        | bigint(20)   | NO   |     | NULL    |                |
    | l_id        | bigint(20)   | NO   |     | NULL    |                |
    +-------------+--------------+------+-----+---------+----------------+

    +-------------+---------------+------+-----+---------+----------------+
    | Field       | Type          | Null | Key | Default | Extra          |
    +-------------+---------------+------+-----+---------+----------------+
    | u_id        | bigint(20)    | NO   | PRI | NULL    | auto_increment |
    | salutation  | varchar(10)   | NO   |     | NULL    |                |
    | first_name  | varchar(25)   | NO   |     | NULL    |                |
    | last_name   | varchar(25)   | NO   |     | NULL    |                |
    +-------------+---------------+------+-----+---------+----------------+

人们的工作

    +-------------+------------+------+-----+---------+----------------+
    | Field       | Type       | Null | Key | Default | Extra          |
    +-------------+------------+------+-----+---------+----------------+
    | pj_id       | bigint(20) | NO   | PRI | NULL    | auto_increment |
    | u_id        | bigint(20) | NO   |     | NULL    |                |
    | j_id        | bigint(20) | NO   |     | NULL    |                |
    | l_id        | bigint(20) | NO   | MUL | NULL    |                |
    +-------------+------------+------+-----+---------+----------------+

我需要制作一个显示

的表格
    +----------+-------------------------+------------+------------+------------+
    | b_id     | b_name                  | Locations  | Jobs       | People     |
    +----------+-------------------------+------------+------------+------------+
    |       21 | Widgets Inc             |          0 |          x |          0 |
    |       24 | Prince Privates         |          0 |          0 |          0 |
    |       23 | Halon plc               |          x |          0 |          0 |
    |       18 | Stinky Hotels           |          x |          x |          x |
    |       20 | Pylon Catering Corps    |          x |          x |          x |
    |       22 | Skytrain Biscuits       |          0 |          0 |          0 |
    +----------+-------------------------+------------+------------+------------+

我可以通过以下方式为每个业务实现正确的匹配位置计数:

SELECT b.b_id,
       b.b_name,
       count(l.l_id) AS locations
FROM business AS b
LEFT JOIN locations AS l ON b.b_id=l.b_id
GROUP BY b.b_id
ORDER BY b_name

如果我将其扩展到包括每个企业的工作数量,然后计算每个企业的人数,那么这一切都会变成梨形。

我知道以下在获得人数方面本质上是错误的(因为人们可以容纳超过1份工作)。我不知道我是否需要使用子选择或COALESCE?

SELECT b.b_id,
       b.b_name,
       count(l.l_id) AS locations,
       count(j.j_id) AS jobs,
       count(p.u_id) AS people
FROM business AS b
LEFT JOIN locations AS l ON b.b_id=l.b_id
LEFT JOIN job AS j ON b.b_id=j.b_id
LEFT JOIN people_jobs AS p ON l.l_id=p.l_id
GROUP BY b.b_id
ORDER BY b_name

3 个答案:

答案 0 :(得分:3)

我认为您可以使用count(distinct)快速修复查询:

SELECT b.b_id, b.b_name,
       count(distinct l.l_id) AS locations,
       count(distinct j.j_id) AS jobs,
       count(distinct p.u_id) AS people
FROM business b LEFT JOIN
     locations l
     ON b.b_id = l.b_id LEFT JOIN
     job j
     ON b.b_id = j.b_id LEFT JOIN
     people_jobs p
     ON l.l_id = p.l_id
GROUP BY b.b_id
ORDER BY b_name ;

问题可能只是joinpeople_jobs需要更多条件:

     people_jobs p
     ON l.l_id = p.l_id and j.j_id = p.j_id

可能是u上的条件。

您的问题是,您正尝试跨多个维度进行汇总,并为每个业务获取笛卡尔积。有时需要的替代方法是在子查询中进行计数。

答案 1 :(得分:1)

此查询应该满足您的需求:

SELECT
  b.b_id,
  b.b_name,
  (SELECT COALESCE(COUNT(l_id         ),0) FROM locations WHERE b_id=b.b_id) AS locations,
  (SELECT COALESCE(COUNT(j_id         ),0) FROM jobs      WHERE b_id=b.b_id) AS jobs,
  (SELECT COALESCE(COUNT(DISTINCT u_id),0)
     FROM jobs        j
     JOIN people_jobs pj ON pj.j_id=j.j_id
     WHERE j.b_id=b.b_id
  ) AS people
FROM business as b
ORDER BY b_name

如果使用subSELECT,则不需要GROUP BY,因为外部查询将每个b_id返回1行,不再有。

如果你在主要查询级别加入4个表,就像你在做的那样,你有两个困难:

  • 行数增加(可通过GROUP BY避免)
  • 一个简单的COUNT无法正常工作(使用COUNT可以避免(DISTINCT ...))

(如戈登的回答所示)

答案 2 :(得分:0)

您可以尝试此查询: -

SELECT b.b_id,b.b_name,count(l.l_id) AS locations,count(j.j_id) AS jobs,count(p.u_id) AS people
FROM business as b LEFT JOIN locations as l ON b.b_id=l.b_id 
LEFT JOIN job as j ON b.b_id=j.b_id 
LEFT JOIN people_jobs as p ON l.l_id=p.l_id 
GROUP BY b.b_id, b.b_name  
ORDER BY b_name 

我希望这对你有用。