MySQL JOIN和COUNT不一致

时间:2011-07-18 16:25:01

标签: mysql

我有这些表格:

mysql> desc mod_asterisk_booking;
+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| id            | int(10) unsigned | NO   | PRI | NULL    | auto_increment | 
| uid           | int(10) unsigned | NO   |     | NULL    |                | 
| server_id     | int(10) unsigned | NO   |     | NULL    |                | 
| date_call     | datetime         | NO   |     | NULL    |                | 
| participants  | int(10) unsigned | NO   |     | NULL    |                | 
| ...                                                                      |
+---------------+------------------+------+-----+---------+----------------+

mysql> desc mod_asterisk_servers;
+-------------------+------------------+------+-----+---------+----------------+
| Field             | Type             | Null | Key | Default | Extra          |
+-------------------+------------------+------+-----+---------+----------------+
| id                | int(10) unsigned | NO   | PRI | NULL    | auto_increment | 
| name              | varchar(32)      | NO   |     | NULL    |                | 
| channels_capacity | int(10) unsigned | NO   |     | NULL    |                | 
| ...                                                                          |
+-------------------+------------------+------+-----+---------+----------------+

mysql> desc mod_asterisk_server_phones;
+------------------+------------------+------+-----+---------+----------------+
| Field            | Type             | Null | Key | Default | Extra          |
+------------------+------------------+------+-----+---------+----------------+
| id               | int(10) unsigned | NO   | PRI | NULL    | auto_increment | 
| server_id        | int(10) unsigned | NO   |     | NULL    |                | 
| phone_number     | varchar(15)      | NO   |     | NULL    |                | 
| phone_alias      | varchar(15)      | NO   |     | NULL    |                | 
| extension        | int(10) unsigned | NO   |     | NULL    |                | 
| is_toll_free     | tinyint(1)       | NO   |     | 0       |                | 
| is_allow_foreign | tinyint(1)       | NO   |     | 0       |                | 
+------------------+------------------+------+-----+---------+----------------+

目标是获取一个服务器(来自mod_asterisk_servers),该服务器在给定的日期间隔内有足够的可用频道。此查询

SELECT s.*,
       s.`channels_capacity` - IFNULL(SUM(b.`participants`), 0) as 'channels_available'
  FROM `mod_asterisk_servers` as s 
  LEFT JOIN `mod_asterisk_booking` as b ON (b.server_id=s.id AND (b.date_call BETWEEN '2011-07-30 15:15:00' AND '2011-07-30 17:15:00'))   
 GROUP BY s.id  
 ORDER BY 'channels_available' DESC;

可以返回类似的内容:

+----+-------------+-----+------------------+--------------------+
| id | name        | ... |channels_capacity | channels_available |
+----+-------------+-----+------------------+--------------------+
|  1 | Test server | ... |              150 |                140 | 
+----+-------------+-----+------------------+--------------------+

现在,我想在此查询中添加一些列;特别是与每个服务器相关的电话号码。电话号码可能包含以下组合:

  • 本地电话号码(is_toll_free=0 AND is_allow_foreign=0
  • 免费电话号码,仅限于指定地区(is_toll_free=1 AND is_allow_foreign=0
  • 免费电话号码,允许“扩展”区域(is_toll_free=1 AND is_allow_foreign=1

我试过了这个查询

SELECT s.*,
       s.`channels_capacity` - IFNULL(SUM(b.`participants`), 0) as 'channels_available', 
       count(p1.phone_number) as 'local_phones',
       count(p2.phone_number) as 'toll_free_phones',
       count(p3.phone_number) as 'allow_foreign_phones' 
  FROM `mod_asterisk_servers` as s 
  LEFT JOIN `mod_asterisk_booking` as b ON (b.server_id=s.id AND (b.date_call BETWEEN '2011-07-30 15:15:00' AND '2011-07-30 17:15:00')) 
  LEFT JOIN `mod_asterisk_server_phones` as p1 ON (p1.server_id=s.id AND p1.is_toll_free=0 AND p1.is_allow_foreign=0) 
  LEFT JOIN `mod_asterisk_server_phones` as p2 ON (p2.server_id=s.id AND p2.is_toll_free=1 AND p2.is_allow_foreign=0) 
  LEFT JOIN `mod_asterisk_server_phones` as p3 ON (p3.server_id=s.id AND p3.is_toll_free=1 AND p3.is_allow_foreign=1) 
 ORDER BY 'channels_available' DESC;

但它返回

+----+-------------+-----+-------------------+--------------------+--------------+------------------+----------------------+
| id | name        | ... | channels_capacity | channels_available | local_phones | toll_free_phones | allow_foreign_phones |
+----+-------------+-----+-------------------+--------------------+--------------+------------------+----------------------+
|  1 | Test server | ... |               150 |                140 |            2 |                2 |                    2 | 
+----+-------------+-----+-------------------+--------------------+--------------+------------------+----------------------+

即使该服务器只有三个数字:

mysql> select * from mod_asterisk_server_phones where server_id = 1;
+----+-----------+----------------+-------------+-----------+--------------+------------------+
| id | server_id | phone_number   | phone_alias | extension | is_toll_free | is_allow_foreign |
+----+-----------+----------------+-------------+-----------+--------------+------------------+
|  1 |         1 | XXX-XXX-XXXX   |             |      XXXX |            0 |                0 | 
|  2 |         1 | 1-800-XXX-XXXX |             |      XXXX |            1 |                0 | 
|  3 |         1 | 1-800-XXX-XXXX |             |      XXXX |            1 |                1 | 
+----+-----------+----------------+-------------+-----------+--------------+------------------+

也许对SQL有更好理解的人可以帮我解决这个问题?

谢谢!

1 个答案:

答案 0 :(得分:1)

尝试使用count(DISTINCT p1.phone_number)代替count(p1.phone_number)(对于p2,p3也是如此)。并且不要忘记正确的GROUP BY