【问题标题】:Understanding the differences between CUBE and ROLLUP了解 CUBE 和 ROLLUP 之间的区别
【发布时间】:2011-10-26 13:51:50
【问题描述】:

我的任务要求我找出“每个日期写了多少张发票?”

我有点卡住了,向我的教授寻求帮助。她给我发了一封邮件来回答这个问题,“每种类型和版本的炉灶有多少? 对于一个挑战但没有加分,包括炉灶的总数。”

这是她发给我的查询:

SELECT STOVE.Type + STOVE.Version AS 'Type+Version'
, COUNT(*) AS 'The Count'
FROM STOVE
GROUP BY STOVE.Type + STOVE.Version WITH ROLLUP;

所以,我调整了该查询,直到它满足我的需求。这是我想出的:

SELECT InvoiceDt
, COUNT(InvoiceNbr) AS 'Number of Invoices' 
FROM INVOICE 
GROUP BY InvoiceDt WITH ROLLUP 
ORDER BY InvoiceDt ASC;

它返回了我想要的以下结果。

无论如何,我决定阅读 ROLLUP 子句并从Microsoft 的一篇文章开始。它说 ROLLUP 子句类似于 CUBE 子句,但它与 CUBE 子句的区别如下:

  1. CUBE 生成一个结果集,显示所选列中所有值组合的聚合。
  2. ROLLUP 生成一个结果集,显示所选列中值层次结构的聚合。

因此,我决定将查询中的 ROLLUP 替换为 CUBE,看看会发生什么。他们产生了相同的结果。我想这就是我感到困惑的地方。

看起来,如果您使用的是我在这里的查询类型,那么这两个子句之间没有任何实际区别。那正确吗?或者,我不明白什么?当我读完微软的文章时,我曾想,使用 CUBE 子句我的结果应该会有所不同。

【问题讨论】:

    标签: sql sql-server sql-server-2008 tsql


    【解决方案1】:

    您不会看到任何差异,因为您只是滚动一列。考虑一个我们这样做的例子

    ROLLUP (YEAR, MONTH, DAY)

    使用ROLLUP,它将具有以下输出:

    YEAR, MONTH, DAY
    YEAR, MONTH
    YEAR
    ()
    

    使用CUBE,它将具有以下内容:

    YEAR, MONTH, DAY
    YEAR, MONTH
    YEAR, DAY
    YEAR
    MONTH, DAY
    MONTH
    DAY
    ()
    

    CUBE 基本上包含每个节点的所有可能汇总方案,而 ROLLUP 将保持层次结构完整(因此它不会跳过 MONTH 并显示 YEAR/DAY,而 CUBE 会)

    这就是为什么您没有看到差异的原因,因为您只有一个列正在滚动。

    希望对您有所帮助。

    【讨论】:

    • 有趣。我想知道为什么设计师不只是选择一个并添加一个额外的属性参数来说明它的行为方式。为一些基本相同但略有不同的东西命名是很愚蠢的。
    【解决方案2】:

    我们可以通过一个简单的例子来理解 ROLLUP 和 CUBE 的区别。考虑我们有一个表格,其中包含学生季度测试的结果。在某些情况下,我们需要查看与该季度以及学生对应的总数。这是示例表

    SELECT * INTO #TEMP
    FROM
    (
        SELECT 'Quarter 1' PERIOD,'Amar' NAME ,97 MARKS
        UNION ALL
        SELECT 'Quarter 1','Ram',88 
        UNION ALL
        SELECT 'Quarter 1','Simi',76 
        UNION ALL
        SELECT 'Quarter 2','Amar',94 
        UNION ALL
        SELECT 'Quarter 2','Ram',82 
        UNION ALL
        SELECT 'Quarter 2','Simi',71 
        UNION ALL
        SELECT 'Quarter 3' ,'Amar',95 
        UNION ALL
        SELECT 'Quarter 3','Ram',83 
        UNION ALL
        SELECT 'Quarter 3','Simi',77
        UNION ALL
        SELECT 'Quarter 4' ,'Amar',91 
        UNION ALL
        SELECT 'Quarter 4','Ram',84 
        UNION ALL
        SELECT 'Quarter 4','Simi',79
    )TAB
    

    1. ROLLUP(可以找到对应一列的总数)

    (a) 获取每个学生在所有季度的总分。

    SELECT * FROM #TEMP
    UNION ALL
    SELECT PERIOD,NAME,SUM(MARKS) TOTAL
    FROM #TEMP
    GROUP BY NAME,PERIOD 
    WITH ROLLUP
    HAVING PERIOD IS NULL AND NAME IS NOT NULL 
    // Having is used inorder to emit a row that is the total of all totals of each student
    

    以下是(a)的结果

    (b) 如果你需要得到每个季度的总分

    SELECT * FROM #TEMP
    UNION ALL
    SELECT PERIOD,NAME,SUM(MARKS) TOTAL
    FROM #TEMP
    GROUP BY PERIOD,NAME 
    WITH ROLLUP
    HAVING PERIOD IS NOT NULL AND NAME IS NULL
    

    以下是(b)的结果

    2。 CUBE(一次性查找 Quarter 和学生的总数)

    SELECT PERIOD,NAME,SUM(MARKS) TOTAL
    FROM #TEMP
    GROUP BY NAME,PERIOD 
    WITH CUBE
    HAVING PERIOD IS NOT NULL OR NAME IS NOT NULL
    

    以下是CUBE的结果

    现在您可能想知道 ROLLUP 和 CUBE 的实时使用。有时我们需要一份报告,我们需要在其中一次查看每个季度的总数和每个学生的总数。这是一个例子

    我正在稍微更改上面的 CUBE 查询,因为我们需要两个总计的总计。

    SELECT CASE WHEN PERIOD IS NULL THEN 'TOTAL' ELSE PERIOD END PERIOD,
    CASE WHEN NAME IS NULL THEN 'TOTAL' ELSE NAME END NAME,
    SUM(MARKS) MARKS
    INTO #TEMP2
    FROM #TEMP
    GROUP BY NAME,PERIOD 
    WITH CUBE
    
    DECLARE @cols NVARCHAR (MAX)
    
    SELECT @cols = COALESCE (@cols + ',[' + PERIOD + ']', 
                   '[' + PERIOD + ']')
                   FROM    (SELECT DISTINCT PERIOD FROM #TEMP2) PV  
                   ORDER BY PERIOD    
    
    
    DECLARE @query NVARCHAR(MAX)
    SET @query = 'SELECT * FROM 
                 (
                     SELECT * FROM #TEMP2
                 ) x
                 PIVOT 
                 (
                     SUM(MARKS)
                     FOR [PERIOD] IN (' + @cols + ')
                ) p;' 
    
    EXEC SP_EXECUTESQL @query
    

    现在你会得到以下结果

    【讨论】:

    • 您好。根据您的示例,如果您需要查找两列的聚合(例如季度和学生?),是否可以说 CUBE 最好使用,而 ROLLUP 更适合单列?
    【解决方案3】:

    这是因为您只有一列作为分组依据。

    添加Group by InvoiceDt, InvoiceCountry(或任何可以为您提供更多数据的字段。

    With Cube 将为您提供每个 InvoiceDt 的 Sum,您将获得每个 InvoiceCountry 的 Sum。

    【讨论】:

      【解决方案4】:

      您可以找到有关 GROUPING SET、CUBE、ROLL UP 的更多详细信息。 TL;DR 他们只是以某种方式扩展 GROUP BY + UNION ALL 以获得聚合:)

      https://technet.microsoft.com/en-us/library/bb510427(v=sql.105).aspx

      【讨论】:

        【解决方案5】:

        所有投票的答案都很好。


        一般来说,一个重要的区别是

        1. ROLLUP 规范的 N 个元素对应于 N+1 GROUPING 集。
        2. CUBE 规范的 N 个元素对应于 2^N GROUPING 集。

        Further reading see my article with respect to spark sql

        例如:

        store_id,product_type

        汇总等价于

        GROUP BY store_id,product_type
         GROUPING SETS (
        (store_id,product_type)
        ,(product_type)
        , ())
        

        for 2 (n) group by columns 分组集有 (n+1 ) = 3 个列组合

        立方体等价于

        GROUP BY store_id,product_type
         GROUPING SETS (
        (store_id,product_type)
        ,(store_id)
        ,(product_type)
        , ())
        

        for 2 (n) group by columns 分组集有 (2^n) = 4 个列组合

        【讨论】:

          猜你喜欢
          • 2019-01-13
          • 2019-10-30
          • 2011-05-16
          • 1970-01-01
          • 2020-03-22
          • 1970-01-01
          • 1970-01-01
          • 2023-03-03
          • 2017-07-26
          相关资源
          最近更新 更多