SQL SERVER – Introduction to Rollup Clause

In this article we will go over basic understanding of Rollup clause in SQL Server. ROLLUP clause is used to do aggregate operation on multiple levels in hierarchy. Let us understand how it works by using an example.

Consider a table with the following structure and data:

CREATE TABLE tblPopulation (
Country VARCHAR(100),
[State] VARCHAR(100),
City VARCHAR(100),
[Population (in Millions)] INT
)
GO
INSERT INTO tblPopulation VALUES('India', 'Delhi','East Delhi',9 )
INSERT INTO tblPopulation VALUES('India', 'Delhi','South Delhi',8 )
INSERT INTO tblPopulation VALUES('India', 'Delhi','North Delhi',5.5)
INSERT INTO tblPopulation VALUES('India', 'Delhi','West Delhi',7.5)
INSERT INTO tblPopulation VALUES('India', 'Karnataka','Bangalore',9.5)
INSERT INTO tblPopulation VALUES('India', 'Karnataka','Belur',2.5)
INSERT INTO tblPopulation VALUES('India', 'Karnataka','Manipal',1.5)
INSERT INTO tblPopulation VALUES('India', 'Maharastra','Mumbai',30)
INSERT INTO tblPopulation VALUES('India', 'Maharastra','Pune',20)
INSERT INTO tblPopulation VALUES('India', 'Maharastra','Nagpur',11 )
INSERT INTO tblPopulation VALUES('India', 'Maharastra','Nashik',6.5)
GO

SQL SERVER - Introduction to Rollup Clause rollup1

Now, we need to create a report on population at 3 levels: City, State and Country.

Can we do it by using SUM with GROUP BY clause?

Yes, we can, but we will have to write a separate query to GROUP BY at each level and then union the result of all queries; even after this, the proper ordering or the result would still need more work.

However, SQL Server provides a very easy solution. Just add the WITH ROLLUP clause in GROUP BY and you get the desired results.

SELECT Country,[State],City,
SUM ([Population (in Millions)]) AS [Population (in Millions)]
FROM tblPopulation
GROUP BY Country,[State],City WITH ROLLUP

SQL SERVER - Introduction to Rollup Clause rollup2

Let me know if this explanation is easy to understand.

Reference: Pinal Dave (https://blog.sqlauthority.com)

Business Intelligence, SQL Scripts, SQL Server
Previous Post
SQLAuthority News – Blog Subscription and Comments RSS
Next Post
SQLAuthority News – MUGH – Microsoft User Group Hyderabad – Feb 2, 2010 Session Review

Related Posts

68 Comments. Leave new

  • Dear Pinal,
    Excellent article regarding rollup clause.

    i generally use ROLLUP like this
    ——————————————————————-
    SELECT COUNTRY, STATE, CITY, SUM([Population (in Millions)]) FROM dbo.TBLPOPULATION
    GROUP BY ROLLUP(COUNTRY, STATE, CITY)
    ——————————————————————–
    i didnt find any difference in Performance.

    which way could be better? coz
    Microsoft plans to remove WITH ROLLUP clause in future version

    ms-help://MS.SQLCC.v10/MS.SQLSVR.v10.en/s10de_6tsql/html/40075914-6385-4692-b4a5-62fe44ae6cb6.htm

    can v use like this ROLLUP(column1,column2)? or any drawbacks in this method.

    Reply
    • Nimisha Thanawala
      August 4, 2010 5:17 pm

      Hello siva,

      i tried to use rollup with ur query but i received an error.

      “The CUBE() and ROLLUP() grouping constructs are not allowed in the current compatibility mode. They are only allowed in 100 mode or higher.”

      I am using SQL Server 2008.

      Reply
      • dear pinal ,
        my query is also wrkng like the one said by siva….and no more errors…result is equivalent to using with rollup…I mean

        SELECT COUNTRY, STATE, CITY, SUM([Population (in Millions)]) FROM dbo.TBLPOPULATION
        GROUP BY ROLLUP(COUNTRY, STATE, CITY)

        is wrkng with me…

      • do like this Compatibility error will go
        ALTER DATABASE dbName SET COMPATIBILITY_LEVEL = 100

      • 2008 R2 and up

    • hi pinal,
      the explanation u provided is very precise….
      understood in one read only….

      Reply
    • Hi .Thanks for the great article.But I do get an error when trying to manipulate a table which uses a rollup clause for futher processing. eg by making a slight change into your code(adding the “into tbl_tempHolder”) string to your code
      SELECT Country,[State],City,
      SUM ([Population (in Millions)]) AS [Population (in Millions)] into tbl_tempHoder
      FROM tblPopulation
      GROUP BY Country,[State],City WITH ROLLUP
      I get this error

      Attempting to set a non-NULL-able column’s value to NULL.

      In my case I would now want to get the aggregated totals into another table and order them then and assign positions to them.

      Assuming tbl_tempHoder has been populated this would be my final table after further processing

      City | Total | Position
      ————————————
      Mahastra | 67 | 1
      ———————————
      Dehli | 29 | 2
      ———————————-
      Karnataka| 12 | 3

      Is there any way you can suggest to manipulate the totals without the requirement of creating a temporary table which then results in the error.

      If I do the following without a roll up clause

      SET NOCOUNT ON;
      IF object_id(‘tbl_ferma’) IS NOT NULL
      BEGIN
      DROP TABLE [dbo].[tbl_ferma]
      END
      SELECT State,
      SUM ([Population (in Millions)]) AS [Population (in Millions)] into tbl_ferma
      FROM tblPopulation
      GROUP BY State

      and querying the table

      select * from tbl_ferma order by [Population (in Millions)] desc

      I get

      City | Total |
      ————————————
      Mahastra | 67 |
      ———————————
      Dehli | 29 |
      ———————————-
      Karnataka| 12 |

      And am struggling on how to get the actual position of a record which i want to insert into another table so that i could use in in a certain report.

      Hope you will be able to help.

      Best ,Abide

      Reply
    • Mohammed Abdul Gadir
      December 31, 2012 5:13 pm

      You are great man thanks;

      Reply
    • Siva – in your approach, you can include or exclude the rollup from any column. Like, you can use GROUP BY Country, [State], Rollup( City) to rollup only at City Level.

      The one mentioned in the article runs it on all the columns in Group By clause. I compared it both ways and there is no impact on the subtree cost.

      Reply
  • Hi Pinal,

    Can you please also include that,

    If we apply Rollup (a,b,c) then it acts as (a,b,c) (a,b) (a) ()

    Now in SQL Server 2008, Rollup is implemented as subclause of GROUP BY clause.

    i.e., the syntax in SQL Server 2008 would be:

    SELECT Country,[State],City,
    SUM ([Population (in Millions)]) AS [Population (in Millions)]
    FROM tblPopulation
    GROUP BY ROLLUP(Country,[State],City)

    Reply
  • You shouldn’t use ROLLUP operator in sql until there is no other option. It is actually a job of a reporting tool to display summary informations to each group.

    If you do it via sql, there is not a easy way to uniquely identify a row also it is a performation problem for large number of data

    Reply
    • @Madhivanan

      “If you do it via sql, there is not a easy way to uniquely identify a row”

      Check out GROUPING(). It makes it very easy.

      Reply
      • You can use GROUPING function. But you need to depend on that. Also did you test running a query involving GROUPING with ROLLUP or CUBE?

        Also as I specified in my first reply, it should be done in a reporting tool

      • @Madhivanan

        I am currently using ROLLUP because i need different totals in a query. It uses the numbers for further calculations. Without ROLLUP i would need to run the query a second time with another GROUP BY clause adding unneeded complexity to the query.

        ROLLUP with GROUPING works well.

  • Pinal, very interesting. Just yesterday i used ROLLUP in a query (and toyed with CUBE, not sure if i need it yet.) And, i responded to someone’s question with it (but they didn’t use it):

    Interesting how thing come together like that.

    I’d suggest that you explain GROUPING() as well. Otherwise, the NULLs are not really trustworthy. They may be unknown, that may be the grouping identifier.

    I went for a smaller basic test to see it myself.

    WITH
    A(A, B, C)
    AS
    (
    SELECT 1, 1, 1 UNION ALL
    SELECT 1, 1, 2 UNION ALL
    SELECT 1, 2, 1 UNION ALL
    SELECT 1, 2, 1 UNION ALL
    SELECT 2, 1, 1 UNION ALL
    SELECT 2, 1, 2 UNION ALL
    SELECT 2, 2, 1 UNION ALL
    SELECT 2, 2, 1
    )
    SELECT
    A,
    B,
    SUM(C),
    GROUPING(A),
    GROUPING(B)
    FROM
    A
    GROUP BY
    A,
    B
    WITH ROLLUP; –CUBE;

    Reply
  • Hi,
    I agree with Madhivanan, for summarisation reporting tools can provide complex group by’s for example ssrs 2008 has very good row and column groupings. Most of the rollup like capabilties have been handled at the reports by me.

    Thank you

    Reply
  • charlie arehart
    February 24, 2010 8:28 pm

    @Madhivanan, you say “If you do it via sql, there is not a easy way to uniquely identify a row”.

    Do you mean no way to identify what rows are rollup totals? Actually, you can identify that. See the Grouping function. You can use grouping(colname) and it will be 1 if the rollup is for that column.

    Using a CASE clause with that (to identify when the value is 1 and output a descriptive column value), you can get the kind of identification I think you seek. Let us know if it helps.

    Reply
  • yes thnkx a lot…
    your way of explanation is always easy to understand…

    and my i que… ? before going more or searching any thing…
    is ROLLUP awailable in Sql server 2005 ?
    and ROLLUP must be available in all upper versions ….

    so i just want to confirm about SS 2005.. is it ?

    thnx

    Reply
  • Hello Sandeep,

    In this article I demonstrated this functionality in SQL Server 2005. Even this is supported in 2008 but a recommonded syntax that would be supported in future versions is:

    SELECT Country,[State],City,
    SUM ([Population (in Millions)]) AS [Population (in Millions)]
    FROM tblPopulation
    GROUP BY ROLLUP (Country,[State],City)

    Regards,
    Pinal Dave

    Reply
  • The same can be achieve thru grouping sets isnt it?

    Reply
  • Hi,

    I dont see Rollup inbuilt function in SQL Server 2005. Any headsup why I am not able to use this function?

    Thanks,
    Raj

    Reply
    • @Raj

      Here is an example:

      WITH
      A(A, B, C)
      AS
      (
      SELECT 1, 1, 1 UNION ALL
      SELECT 1, 1, 2 UNION ALL
      SELECT 1, 2, 1 UNION ALL
      SELECT 1, 2, 1 UNION ALL
      SELECT 2, 1, 1 UNION ALL
      SELECT 2, 1, 2 UNION ALL
      SELECT 2, 2, 1 UNION ALL
      SELECT 2, 2, 1
      )
      SELECT
      A,
      B,
      SUM(C),
      GROUPING(A),
      GROUPING(B)
      FROM
      A
      GROUP BY
      A,
      B
      WITH ROLLUP; –CUBE;

      Reply
      • Thanks Brian,

        Interesting, Your query works. I still trying to understand example provided at the beginning of this Post. Your Comment helped.

        Raj

      • @Raj

        You’re welcome. I was toying with it myself and my efforts helped you too. I’m so excited. :)

        Now, you have to teach me something!

    • Can you post the code that didn’t work?

      Reply
  • good article

    Reply
  • Feodor Georgiev
    March 11, 2010 3:29 pm

    I think the Rollup and Cube functions have been with SQL Server since 6.5, am I wrong?

    Reply
  • Hello Feodor,

    You are right. ROLLUP is available since SQL Server 6.5.

    Regards,
    Pinal Dave

    Reply
  • Please Help me out of this problem how can i add sum of overdue and due using rollup

    this is stored procedure

    create procedure damaka
    (@EMP_CODE VARCHAR(15),
    @MONTH VARCHAR(10),
    @WEEK VARCHAR(10),
    @DEMAND_DATE DATETIME
    )
    AS
    IF @MONTH>=’28’
    BEGIN
    –OPEN CASES
    SELECT d.file_no AS FileNo,d.hirer_name as CustomerName,demand_month1.due_amt As OverDue,d.instalment as Due FROM demand_month1 d where(EMP_CODE=@EMP_CODE AND demand=@MONTH AND Closing>@DEMAND_DATE)
    UNION all
    SELECT W.file_no as FileNo,W.hirer_name as CustomerName,convert(char(10),W.Starting,103) as Starting,convert(char(10),W.Closing,103) as Closing,W.Mode,W.due_AMT as OverDue,W.instalment as Due from demand_week1 W where EMP_CODE=@EMP_CODE AND demand=@WEEK AND Closing>@DEMAND_DATE
    else
    select W.file_no as FileNo,W.hirer_name as CustomerName,W.due_AMT as OverDue,W.due_AMT as Due,” as SlipDate, ” as SlipNo from W where((EMP_CODE=@EMP_CODE AND demand=@WEEK AND W.Closing0 AND closing<@DEMAND_DATE))
    UNION all
    SELECT HIRER.file_no as FileNo,HIRER.hirer_name as CustomerName,overdue.due_amt as OverDue, overdue.DUE_AMT as Due FROM HIRER INNER JOIN OVERDUE ON HIRER.FILE_NO=OVERDUE.FILE_NO WHERE EMP_CODE=@EMP_CODE AND MODE='D' AND HIRER.Closing<@DEMAND_DATE order by closing desc
    END

    Reply
  • plz help me in this problem

    can we use with rollup in above problem

    Reply
  • hi,
    i want to use group by clause with joins in stored procedure..
    how can i achieve it,is there any rules to use group by clause in stored procedure with joins.

    i tried but i didn’t succeed.

    please can u send any sample to achieve it.

    thanks..

    Reply
    • Marko Parkkola
      April 22, 2010 7:23 pm

      Same rules apply when grouping outside the procedure. It’s impossible to say what went wrong with your query without seeing the actual statement. But here’s my two cents…

      GROUP BY is unfortunately not the easiest thing to understand. Especially if you start up with MySQL where you can return any fields you like from the query and not just those in the group (+ aggregated fields). Probably the basic rule is that:

      – You can return only those fields you use in GROUP BY
      – Addition to that, you can return aggregated fields also, like SUM(somefield) and AVG(somefield)

      When dealing with views, procedures and functions, if you return aggregated values you need specify names for the fields. For example:

      SELECT [Order], SUM([Price]) AS [Price]
      FROM [Orders]
      GROUP BY [Order]

      Joins does not make exceptions to these rules. No matter how many joins you make, how complex they are, grouping rules are still the same.

      Sometimes you need to group and calculate some values and return other values also. In that case you need joins and subqueries like this (and this is very bad example):

      SELECT p.[Purchaser], g.[Order], g.[Price]
      FROM Purchaser p
      JOIN (SELECT [Order], SUM([Price]) [Price] FROM [Orders] GROUP BY [Order]) g ON g.[Order] = p.[Order]

      Well, I can’t come up with anything else. I hope this helps. Now I have to clean up the mess my 1,5 year daughter just made when I was writing this :)

      Reply
  • Nice Solution Marko,

    may be problem with sub queries in my case,

    thanks marko, now i able to do.

    Reply
  • I thank you for for all your articles; very easy to understand.

    Could you please explain a practical use of WITH CUBE clause?

    Thanks

    Reply
    • It is maninly used to generate detail data along with summary data. See the output

      Reply
      • When WITH CUBE clause is used every row is subtotaled along with other combinations. The output is not sorted and difficult to understand. Is there any way the result can be sorted?

        Thanks

    • Hi all,

      I am doing a rollup with grouping, and I was wondering if there is a way for me to only round the subtotals.
      I’ve included a simplified example of what I want to do. After running the Select Script, I want only the ‘Total_Costs’ for all ‘Report Total’ to be rounded.
      I’ve tried a few variations of case statements but was unable to get it to work.

      –Table Creation

      CREATE TABLE [dbo].[SalesItems](
      [Product] [nchar](10) NULL,
      [Store] [nchar](10) NULL,
      [Cost] [numeric](18, 5) NULL
      )
      GO
      INSERT INTO SalesItems VALUES (‘Chips’,’A’,2.50000)
      INSERT INTO SalesItems VALUES (‘Chips’,’B’,3.00000)
      INSERT INTO SalesItems VALUES (‘Napkins’,’A’,1.90000)
      INSERT INTO SalesItems VALUES (‘Chips’,’B’,3.00000)
      INSERT INTO SalesItems VALUES (‘Napkins’,’B’,2.50000)
      INSERT INTO SalesItems VALUES (‘Dip’,’A’,4.00000)
      INSERT INTO SalesItems VALUES (‘Dip’,’A’,4.30000)
      INSERT INTO SalesItems VALUES (‘Dip’,’B’,3.40000)
      INSERT INTO SalesItems VALUES (‘Chips’,’A’,2.75000)
      INSERT INTO SalesItems VALUES (‘Napkins’,’A’,2.10000)
      INSERT INTO SalesItems VALUES (‘Napkins’,’B’,2.60000)
      GO

      –Select Script

      SELECT CASE WHEN (Grouping(Store) = 1) THEN ‘Report Total’ ELSE Store END AS report_total, Product, Store, SUM(Cost) AS Total_Cost
      FROM SalesItems
      GROUP BY Product, Store WITH ROLLUP
      ORDER BY report_total

      Reply
  • Can we use multiple ROLLUP

    i.e.
    GROUP BY GroupId, Col1 WITH ROLLUP, Col2 WITH ROLLUP

    Reply
  • HI,

    We get total fine…. How I can make “Total” Instead of “NULL” at end(Naming convention )

    Reply

Leave a Reply