在组中包含null / 0行

时间:2013-03-15 18:30:45

标签: sql sql-server group-by

我想查询数据库中的用户以及他们在每个活动类别上花费的时间。这些类别存储在表ActivityCategory(int Id,varchar Name)中。其中只有8个,我希望看到所有这些,即使没人花时间在特定类别上。

我有以下查询:

select u.NoEmploye, u.FirstName, u.LastName, Total=sum(h.NbHeures), ac.Name
from Users u
join Semaines s on u.EntityGuid=s.UserGuid
join HeuresProjets hp on s.Id=hp.WeekId
join Heures h on hp.HPId=h.HpGuid
join ActivityCodes code on h.Code=code.ActivityId
join ActivityCategory ac on code.Categorie=ac.Id
group by u.NoEmploye, u.FirstName, u.LastName, ac.Name
order by u.NoEmploye

它工作正常,但它不会返回未使用的ActivityCategories。我尝试了full / left / right / inner / outer / you-name-it join的每个组合。当没有人使用类别时,我能得到的最好的是完全空行,而对于特定用户不使用但其他人不使用的类别,我将获得null ac.Name。我怀疑group by [...] ac.Name 部分正在“吃掉”未使用的类别。我究竟做错了什么?我应该编写第二个选择查询来对结果进行分组吗?我还有十几个类似的查询要写,所以我想了解而不仅仅是有一个没有解释的固定查询。

修改 Lamak的第二个查询到目前为止工作,但是当我添加where子句时它也有同样的问题。

EDIT2 ypercube'编辑效果很好

现在让我们看看我是否正确理解了查询。 当结果为null时,我将Sum与0合并以具有proprer值。我从ActivityCategory开始选择,以确保我拥有所有这些,甚至是未使用的,我与用户交叉加入,以拥有ActivityCategory和Users的每个组合。我离开加入Activitycodes只获取相关的行,然后我内部加入我的其他表来到Semaine。我的条件应用于Semaine表的连接,因为我想在交叉连接之前过滤我的数据。最后,我按用户和ActivityCategory对数据进行分组以使总和有效。

1 个答案:

答案 0 :(得分:4)

这应该做:

SELECT  u.NoEmploye, u.FirstName, u.LastName, Total=sum(h.NbHeures), ac.Name
FROM ActivityCategory ac
LEFT JOIN ActivityCodes code
    ON code.Categorie=ac.Id
LEFT JOIN Heures h
    ON h.Code=code.ActivityId
LEFT JOIN HeuresProjets hp
    ON hp.HPId=h.HpGuid
LEFT JOIN Semaines s
    ON s.Id=hp.WeekId
LEFT JOIN Users u
    ON u.EntityGuid=s.UserGuid
GROUP BY u.NoEmploye, u.FirstName, u.LastName, ac.Name
ORDER BY u.NoEmploye

基本上,如果您想要所有类别,则需要将该表用作FROM上的第一个表格并对该表格执行LEFT JOIN

<强>更新 如果您希望结果中的每个用户都使用每个类别,则需要CROSS JOIN

SELECT  u.NoEmploye, u.FirstName, u.LastName, Total=sum(h.NbHeures), ac.Name
FROM ActivityCategory ac
CROSS JOIN Users u
LEFT JOIN ActivityCodes code
    ON code.Categorie=ac.Id
LEFT JOIN Heures h
    ON h.Code=code.ActivityId
LEFT JOIN HeuresProjets hp
    ON hp.HPId=h.HpGuid
LEFT JOIN Semaines s
    ON s.Id=hp.WeekId AND u.EntityGuid=s.UserGuid
GROUP BY u.NoEmploye, u.FirstName, u.LastName, ac.Name
ORDER BY u.NoEmploye

要在添加WHERE子句时解决此问题:

SELECT  u.NoEmploye, u.FirstName, u.LastName, 
        Total=COALESCE(SUM(h.NbHeures),0), ac.Name
FROM ActivityCategory ac
CROSS JOIN Users u
LEFT JOIN 
        ActivityCodes code
        JOIN Heures h
            ON h.Code=code.ActivityId
        JOIN HeuresProjets hp
            ON hp.HPId=h.HpGuid
        JOIN Semaines s
            ON s.Id=hp.WeekId 
            AND (some condition on the dates)            -- add here
    ON  ac.Id = code.Categorie
    AND u.EntityGuid = s.UserGuid
GROUP BY u.NoEmploye, u.FirstName, u.LastName, ac.Name
ORDER BY u.NoEmploye