2010-07-12 127 views
8

我有两个表。表A列出了员工姓名。表B是一个复杂的表格,其中包含员工打电话的信息。SQL - 按左连接分组

我的目标是创建一个列'name'和'callCount'的表。我打算通过“左连接”和“分组”来实现这一点,但我一直在思念那些没有打过电话的员工。我怎样才能让它保持名称,并在那里放一个零?

也许我很近,有人可以指出我的错字?在此先感谢您的帮助,这里是SQL:

SELECT A.name, COUNT(B.call_id) AS 'outgoing call count' 
FROM EmployeeTable A 
LEFT JOIN CallTable B 
ON A.name = B.call_from_name 
WHERE B.call_type LIKE 'outgoing' 
AND B.voice_mail = '0' 
... 
GROUP BY A.name 

回答

25

这是一个JOIN不是NULL问题:您的过滤器将OUTER更改为INNER JOIN。这意味着你只有在CallTable(B)中有行的地方才能得到COUNT,而不是你想要的OUTER JOIN。

SELECT A.name, COUNT(B.call_id) AS 'outgoing call count' 
FROM 
    EmployeeTable A 
    LEFT JOIN 
    (
    SELECT call_from_name, call_id FROM CallTable 
    WHERE call_type LIKE 'outgoing' 
    AND voice_mail = '0' 
    AND /* other CallTable filters */ 
    ) B 
    ON A.name = B.call_from_name 
WHERE 
    /* only EmployeeTable A filters */ 
GROUP BY A.name 

编辑:您的评论别处后,你对所有B中的过滤器必须在派生表,而不是在外部哪里。

+0

太好了,非常感谢! :) – Brandi 2010-07-12 20:35:26

+3

当你不需要通配符比较时,要小心使用LIKE。它可以真正杀死你的查询速度。只是做一个常规的平等比较:WHERE call_type ='传出' – 2010-07-12 20:48:19

+2

有关进一步解释: http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN – HLGEM 2010-07-12 21:44:39

2

由于您使用的是LEFT JOIN,在左侧定义表中引用JOIN可以为空。行在那里,你只是没有看到计数值为零。你需要这意味着这个NULL值转换为零(在这种情况下):

SELECT A.name, 
      COALESCE(COUNT(B.call_id), 0) AS 'outgoing call count' 
    FROM EmployeeTable A 
LEFT JOIN CallTable B ON B.call_from_name = A.name 
        AND B.call_type LIKE 'outgoing' 
        AND B.voice_mail = '0' 
    WHERE ... 
GROUP BY A.name 

这个例子使用COALESCE,处理NULL值的ANSI标准方法。它将返回第一个非空值,但如果找不到任何值,它将返回空值。 ISNULL是SQL Server上的有效替代方案,但在COALESCE时它不能移植到其他数据库。这里是an MSDN article comparing the two functions

+0

COALESCE不需要:它是B上的WHERE子句过滤器使其成为INNER JOIN – gbn 2010-07-12 20:29:11

+0

我试过ISNULL和COALESCE,两者都给出相同的结果。我可能会做一些其他的错误?我列出的条款比我列出的要多,但它们都是确定计数所必需的。 – Brandi 2010-07-12 20:31:53