如何使用汇总计算不同的值?

时间:2014-05-16 18:03:21

标签: sql sql-server sql-server-2000

我有一个包含网络事件日志的表。每个事件都附在一个站点和一个部门。

我使用汇总查询来总结我的所有事件(总停机时间......),并使用ROLLUP函数:

SELECT i.annee, i.mois, i.siteId, count(i.id), sum(i.downtime)
FROM incident i
GROUP BY i.annee, i.mois, i.siteId, i.id
WITH ROLLUP

我按网站对事件进行分组,但我想添加一列,列出每一行与这些事件有关的不同部门的数量。

所以我应该添加一个字段:COUNT(DISTINCT i.department),但我听说它与ROLLUP function不兼容

你知道解决方法吗?

1 个答案:

答案 0 :(得分:1)

以下是3种不同的选择。我没有SQL 2000来测试,但这应该工作。鉴于表格大小和数据结构,每个选项的执行方式可能不同。

注意:对于看到此答案的任何人,如果您使用的是SQL Server 2008 R2或更高版本,那么COUNT DISTINCT即使在使用ROLLUP时也能正常工作。它可能适用于SQL 2005,但我没有要测试的SQL 05实例。

使用子查询:

SELECT t.annee, t.mois, t.siteId, t.id, t.cnt, t.downtime
    , (
        SELECT count(distinct i2.department) 
        FROM incident i2 
        WHERE (i2.annee = t.annee 
                    or i2.annee is null and t.annee is null and t.isgroup_annee = 0 
                    or t.isgroup_annee = 1)
            and (i2.mois = t.mois 
                    or i2.mois is null and t.mois is null and t.isgroup_mois = 0 
                    or t.isgroup_mois = 1)
            and (i2.siteId = t.siteId 
                    or i2.siteId is null and t.siteId is null and t.isgroup_siteId = 0  
                    or t.isgroup_siteId = 1)
            and (i2.id = t.id 
                    OR i2.id is null and t.id is null and t.isgroup_id = 0 
                    OR t.isgroup_id = 1)
        ) as departmentCnt
FROM (
    SELECT i.annee, i.mois, i.siteId, i.id, count(i.id) as cnt, sum(i.downtime) as downtime 
        , grouping(i.annee) AS isgroup_annee
        , grouping(i.mois) AS isgroup_mois
        , grouping(i.siteId) AS isgroup_siteId
        , grouping(i.id) AS isgroup_Id
    FROM incident i
    GROUP BY i.annee, i.mois, i.siteId, i.id
    WITH ROLLUP
) t
;

使用联接:

SELECT t.annee, t.mois, t.siteId, t.cnt, t.downtime
    , count(distinct i2.department) as departmentCnt
FROM (
    SELECT i.annee, i.mois, i.siteId, i.id, count(i.id) as cnt, sum(i.downtime) as downtime 
        , grouping(i.annee) AS isgroup_annee
        , grouping(i.mois) AS isgroup_mois
        , grouping(i.siteId) AS isgroup_siteId
        , grouping(i.id) AS isgroup_Id
    FROM incident i
    GROUP BY i.annee, i.mois, i.siteId, i.id
    WITH ROLLUP
) t
LEFT JOIN incident i2 
    ON (i2.annee = t.annee 
            or i2.annee is null and t.annee is null and t.isgroup_annee = 0 
            or t.isgroup_annee = 1)
    and (i2.mois = t.mois 
            or i2.mois is null and t.mois is null and t.isgroup_mois = 0 
            or t.isgroup_mois = 1)
    and (i2.siteId = t.siteId 
            or i2.siteId is null and t.siteId is null and t.isgroup_siteId = 0  
            or t.isgroup_siteId = 1)
    and (i2.id = t.id 
            OR i2.id is null and t.id is null and t.isgroup_id = 0 
            OR t.isgroup_id = 1)
GROUP BY t.annee, t.mois, t.siteId, t.id, t.cnt, t.downtime, t.isgroup_annee, t.isgroup_mois, t.isgroup_siteId, t.isgroup_Id
;

使用UNIONs手动执行ROLLUP:

SELECT i.annee, i.mois, i.siteId, i.id, count(i.id) as cnt, sum(i.downtime) as downtime, count(distinct i.department) as departmentCnt
FROM incident i
GROUP BY i.annee, i.mois, i.siteId, i.id
UNION ALL
SELECT i.annee, i.mois, i.siteId, null as id, count(i.id) as cnt, sum(i.downtime) as downtime, count(distinct i.department) as departmentCnt
FROM incident i
GROUP BY i.annee, i.mois, i.siteId
UNION ALL
SELECT i.annee, i.mois, null as siteId, null as id, count(i.id) as cnt, sum(i.downtime) as downtime, count(distinct i.department) as departmentCnt
FROM incident i
GROUP BY i.annee, i.mois
UNION ALL
SELECT i.annee, null as mois, null as siteId, null as id, count(i.id) as cnt, sum(i.downtime) as downtime, count(distinct i.department) as departmentCnt
FROM incident i
GROUP BY i.annee
UNION ALL
SELECT null as annee, null as mois, null as siteId, null as id, count(i.id) as cnt, sum(i.downtime) as downtime, count(distinct i.department) as departmentCnt
FROM incident i
;