使用ROLLUP和GROUPING SETS格式化结果

时间:2015-11-09 20:57:13

标签: sql-server sql-server-2008 sql-server-2008-r2

我正在尝试学习SQL Server 2008 R2中的ROLLUPGROUPING SETS运算符。我的表看起来像这样:

+-------+---------+------------+------+-------+----------+------+
| EmpID | EmpName | StartDate  | Type | Units | Account  | Dist |
+-------+---------+------------+------+-------+----------+------+
| 11111 | Alice   | 2015-09-04 | SD20 | 0.500 | 560.2200 |  100 |
| 11111 | Alice   | 2015-09-08 | CCS  | 1.330 | 9P0.6010 |   38 |
| 11111 | Alice   | 2015-09-08 | CCS  | 2.170 | 010.9055 |   62 |
| 11111 | Alice   | 2015-09-10 | SD20 | 0.500 | LP0.3002 |  100 |
| 11111 | Alice   | 2015-09-14 | SD20 | 0.500 | LP0.3002 |  100 |
| 11111 | Alice   | 2015-09-17 | SD20 | 1.000 | LP0.P303 |  100 |
| 11111 | Alice   | 2015-09-18 | SD20 | 1.000 | 600.2200 |  100 |
| 11111 | Alice   | 2015-09-24 | SD20 | 1.000 | LP0.3002 |  100 |
| 11111 | Alice   | 2015-09-25 | SD20 | 1.000 | LP0.3002 |  100 |
| 11111 | Alice   | 2015-09-29 | SD20 | 1.000 | LP0.3002 |  100 |
| 33333 | Carol   | 2015-09-03 | SD20 | 1.000 | 9P0.PP10 |  100 |
| 33333 | Carol   | 2015-09-04 | SD20 | 0.200 | 600.6P62 |   20 |
| 33333 | Carol   | 2015-09-04 | SD20 | 0.800 | 600.6P62 |   80 |
| 33333 | Carol   | 2015-09-25 | SD20 | 1.000 | P50.2100 |  100 |
+-------+---------+------------+------+-------+----------+------+

我希望EmpID和EmpName每个员工显示一次,单位按类型小计,并按EmpID,Type,Account排序,如下:

+-------+---------+----------------+-------+----------+
| EmpID | EmpName |      Type      | Units | Account  |
+-------+---------+----------------+-------+----------+
| 11111 | Alice   |                |       |          |
|       |         | CCS            | 2.17  | 010.9055 |
|       |         | CCS            | 1.33  | 9P0.6010 |
|       |         |       Subtotal | 3.5   |          |
|       |         | SD20           | 0.5   | 560.2200 |
|       |         | SD20           | 1     | 600.2200 |
|       |         | SD20           | 4     | LP0.3002 |
|       |         | SD20           | 1     | LP0.P303 |
|       |         |       Subtotal | 6.5   |          |
| 33333 | Carol   |                |       |          |
|       |         | SD20           | 1     | 600.6P62 |
|       |         | SD20           | 1     | 9P0.PP10 |
|       |         | SD20           | 1     | P50.2100 |
|       |         |       Subtotal | 3     |          |
+-------+---------+----------------+-------+----------+

这是我的查询

select 
case
    when Account is null and Type is null then cast(EmpID as varchar(10))
    else ''
end SubEIN, 
case
    when Account is null and Type is null then EmpName 
    else ''
end SubName, 
case
    when Account is null and Type is not null then 'Subtotal:'
    else isnull(Type, '')
end Type, 
case
    when Account is null and Type is null then ''
    else cast(Units as varchar(10)) 
end Units, 
isnull(Account, '')
from (
    select EmpID, EmpName, Type, sum(Units) AS Units, Account
    from mytable
    group by grouping sets ((EmpID, EmpName), (EmpID, EmpName, Type), (EmpID, EmpName, Account, Type))
) x
order by x.EmpName, x.Type, x.Units, x.Account

我可以使用ROLLUP和/或GROUPING SETS运算符来获取我想要的内容而不是所有CASE个表达式吗?

2 个答案:

答案 0 :(得分:0)

我相信GROUP BY WITH CUBE运算符会让你接近最终目标。使用此方法,您可以选择过滤行或更改空值的显示方式。

select 
    EmpID, 
    EmpName, 
    [Type], 
    Units, 
    Account
from 
    (   
        select 
            EmpID, 
            EmpName, 
            [Type], 
            sum(Units) AS Units, 
            Account
        from mytable
        group by EmpID, EmpName, [Type], Account with CUBE
    ) s
where s.yourfilter

链接:https://technet.microsoft.com/en-us/library/ms175939(v=sql.90).aspx

答案 1 :(得分:0)

你对ROLLUP的期待太多了我觉得 - 这是我的建议样本,我无法完全摆脱CASE-s,但结果看起来像你的目标:

DECLARE @Data TABLE (
    EmpID INT,
    EmpName VARCHAR(100),
    StartDate DATE,
    [Type] VARCHAR(10),
    Units DECIMAL(10, 3),
    Account VARCHAR(100),
    Dist INT
);

INSERT INTO
    @Data
VALUES
    (11111, 'Alice', '2015-09-04', 'SD20', 0.500, '560.2200', 100),
    (11111, 'Alice', '2015-09-08', 'CCS',  1.330, '9P0.6010',  38),
    (11111, 'Alice', '2015-09-08', 'CCS',  2.170, '010.9055',  62),
    (11111, 'Alice', '2015-09-10', 'SD20', 0.500, 'LP0.3002', 100),
    (11111, 'Alice', '2015-09-14', 'SD20', 0.500, 'LP0.3002', 100),
    (11111, 'Alice', '2015-09-17', 'SD20', 1.000, 'LP0.P303', 100),
    (11111, 'Alice', '2015-09-18', 'SD20', 1.000, '600.2200', 100),
    (11111, 'Alice', '2015-09-24', 'SD20', 1.000, 'LP0.3002', 100),
    (11111, 'Alice', '2015-09-25', 'SD20', 1.000, 'LP0.3002', 100),
    (11111, 'Alice', '2015-09-29', 'SD20', 1.000, 'LP0.3002', 100),
    (33333, 'Carol', '2015-09-03', 'SD20', 1.000, '9P0.PP10', 100),
    (33333, 'Carol', '2015-09-04', 'SD20', 0.200, '600.6P62',  20),
    (33333, 'Carol', '2015-09-04', 'SD20', 0.800, '600.6P62',  80),
    (33333, 'Carol', '2015-09-25', 'SD20', 1.000, 'P50.2100', 100)


SELECT
    CASE
        WHEN RN = 0 THEN OrigEmpID
        ELSE NULL 
        END AS EmpID,
    CASE
        WHEN RN = 0 THEN EmpName
        ELSE NULL 
        END AS EmpName,
    CASE
        WHEN RN = 0 THEN NULL
        WHEN RN = 3 THEN 'Subtotal' 
        ELSE [OrigType] 
        END AS [Type],
    Units,
    Account
FROM (
    SELECT DISTINCT
        0 AS RN,
        EmpID AS OrigEmpID, 
        EmpName,
        cast(NULL AS VARCHAR(10)) AS [OrigType],
        cast(NULL AS DECIMAL(10,3)) AS Units,
        cast(NULL AS VARCHAR(100)) AS Account
    FROM
        @Data

    UNION ALL

    SELECT
        CASE WHEN Account IS NULL THEN 3 ELSE 2 END RN,
        EmpID AS OrigEmpID, 
        EmpName, 
        [Type] AS [OrigType],
        sum(Units) AS Units, 
        Account
    FROM
        @Data
    GROUP BY 
        EmpID, EmpName, [Type], ROLLUP(Account)
) data
ORDER BY
    OrigEmpID, [OrigType], RN, Account