• SQL Server ->> GROUPING SETS, CUBE, ROLLUP, GROUPING, GROUPING_ID


    在我们制作报表的时候常常需要分组聚合、多组聚合和总合。如果通过另外的T-SQL语句来聚合难免性能太差。如果通过报表工具的聚合功能虽说比使用额外的T-SQL语句性能上要好很多,不过不够干脆,还是需要先生成整个结果集然后再聚合,而且最最重要的时很多情况下报表的聚合功能可能没办法达到我们需要的效果。GROUPING SETS, CUBE, ROLLUP, GROUPING, GROUPING_ID这几个聚合函数的作用就是在原始语句的基础上完成很多像财务报表需要的聚合功能。

    GROUPING SETS相当于把多个GROUP BY语句通过UNION ALL

    WITH T AS (
    SELECT 'A' A, 'A' B UNION ALL
    SELECT 'A' A, 'B' B UNION ALL 
    SELECT 'A' A, 'C' B UNION ALL
    SELECT 'B' A, 'A' B UNION ALL
    SELECT 'B' A, 'B' B UNION ALL
    SELECT 'B' A, 'C' B UNION ALL
    SELECT 'C' A, 'A' B UNION ALL
    SELECT 'C' A, 'B' B UNION ALL
    SELECT 'C' A, 'C' B)
    
    SELECT  A, B, 
            COUNT(A) AS CNT,
            GROUPING_ID(A,B)
    FROM T
    GROUP BY GROUPING SETS(A, B, ());

    上面代码输出的结果

    通常GROUPING SETS会配合GROUPING_ID或GROUPING函数来完成列的输出,比如聚合列的标签内容。

    GROUPING_ID (a, b, c)  = GROUPING(a) + GROUPING(b) + GROUPING(c)

    GROUPING 用于区分标准空值和由 ROLLUP、CUBE 或 GROUPING SETS 返回的空值。 作为 ROLLUP、CUBE 或 GROUPING SETS 操作结果返回的 NULL 是 NULL 的特殊应用。 它在结果集内作为列的占位符,表示全体。其实意思就是如果列输出为NULL说明是聚合列,不为空就不是聚合列。一开始很难理解。

    SELECT 
        T.[Group]
        ,T.CountryRegionCode
        ,S.Name AS N'Store'
        ,(SELECT P.FirstName + ' ' + P.LastName 
            FROM Person.Person AS P 
            WHERE P.BusinessEntityID = H.SalesPersonID)
            AS N'Sales Person'
        ,SUM(TotalDue)AS N'TotalSold'
        ,CAST(GROUPING(T.[Group])AS char(1)) + 
            CAST(GROUPING(T.CountryRegionCode)AS char(1)) + 
            CAST(GROUPING(S.Name)AS char(1)) + 
            CAST(GROUPING(H.SalesPersonID)AS char(1)) 
            AS N'GROUPING base-2'
        ,GROUPING_ID((T.[Group])
            ,(T.CountryRegionCode),(S.Name),(H.SalesPersonID)
            ) AS N'GROUPING_ID'
        ,CASE 
            WHEN GROUPING_ID(
                (T.[Group]),(T.CountryRegionCode)
                ,(S.Name),(H.SalesPersonID)
                ) = 15 THEN N'Grand Total'
            WHEN GROUPING_ID(
                (T.[Group]),(T.CountryRegionCode)
                ,(S.Name),(H.SalesPersonID)
                ) = 14 THEN N'SalesPerson Total'
            WHEN GROUPING_ID(
                (T.[Group]),(T.CountryRegionCode)
                ,(S.Name),(H.SalesPersonID)
                ) = 13 THEN N'Store Total'
            WHEN GROUPING_ID(
                (T.[Group]),(T.CountryRegionCode)
                ,(S.Name),(H.SalesPersonID)
                ) = 12 THEN N'Store SalesPerson Total'
            WHEN GROUPING_ID(
                (T.[Group]),(T.CountryRegionCode)
                ,(S.Name),(H.SalesPersonID)
                ) = 11 THEN N'CountryRegionCode Total'
            WHEN GROUPING_ID(
                (T.[Group]),(T.CountryRegionCode)
                ,(S.Name),(H.SalesPersonID)
                ) =  7 THEN N'Group Total'
            ELSE N'Error'
            END AS N'Level'
    FROM Sales.Customer AS C
        INNER JOIN Sales.Store AS S
            ON C.StoreID  = S.BusinessEntityID 
        INNER JOIN Sales.SalesTerritory AS T
            ON C.TerritoryID  = T.TerritoryID 
        INNER JOIN Sales.SalesOrderHeader AS H
            ON C.CustomerID = H.CustomerID
    GROUP BY GROUPING SETS ((S.Name,H.SalesPersonID)
        ,(H.SalesPersonID),(S.Name)
        ,(T.[Group]),(T.CountryRegionCode),()
        )
    --HAVING GROUPING_ID(
    --    (T.[Group]),(T.CountryRegionCode),(S.Name),(H.SalesPersonID)
    --    ) = @GroupingLevel
    ORDER BY 
        GROUPING_ID(S.Name,H.SalesPersonID),GROUPING_ID((T.[Group])
        ,(T.CountryRegionCode)
        ,(S.Name)
        ,(H.SalesPersonID))ASC;

    上面代码来自MSDN的例子,数据库是示例数据库--AdventureWork2012

    在只有一列作为GROUP BY CUBE/ROLLUP的列的情况下,两个函数是一样的效果。

    CUBE和ROLLUP的区别就是CUBE比ROLLUP多输出多列的情况下,CUBE比ROLLUP多做的事情就是针对后面列的单独聚合行输出。

    WITH T AS (
    SELECT 'A' A, 'A' B UNION ALL
    SELECT 'A' A, 'B' B UNION ALL 
    SELECT 'A' A, 'C' B UNION ALL
    SELECT 'B' A, 'A' B UNION ALL
    SELECT 'B' A, 'B' B UNION ALL
    SELECT 'B' A, 'C' B UNION ALL
    SELECT 'C' A, 'A' B UNION ALL
    SELECT 'C' A, 'B' B UNION ALL
    SELECT 'C' A, 'C' B)
    
    SELECT  A, B, 
            COUNT(A) AS CNT,
            GROUPING_ID(A,B)
    FROM T
    GROUP BY CUBE(A, B);
    
    
    WITH T AS (
    SELECT 'A' A, 'A' B UNION ALL
    SELECT 'A' A, 'B' B UNION ALL 
    SELECT 'A' A, 'C' B UNION ALL
    SELECT 'B' A, 'A' B UNION ALL
    SELECT 'B' A, 'B' B UNION ALL
    SELECT 'B' A, 'C' B UNION ALL
    SELECT 'C' A, 'A' B UNION ALL
    SELECT 'C' A, 'B' B UNION ALL
    SELECT 'C' A, 'C' B)
    
    SELECT  A, B, 
            COUNT(A) AS CNT,
            GROUPING_ID(A,B)
    FROM T
    GROUP BY ROLLUP(A, B);
  • 相关阅读:
    centos7 安装高版本svn
    idea 常用快捷键
    IDEA 打可执行jar包(maven项目)
    服务器安装JDK
    阿里云服务器连接AWS-S3
    mysql5.7 修改密码,修改权限
    win10 手动安装mysql-8.0.11-winx64.zip
    centos7 关闭防火墙
    centos7 配置阿里云yum源
    centos7 源码安装nginx
  • 原文地址:https://www.cnblogs.com/jenrrychen/p/4620632.html
Copyright © 2020-2023  润新知