<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nathan Griffiths</title>
    <description>The latest articles on DEV Community by Nathan Griffiths (@griffinator76).</description>
    <link>https://dev.to/griffinator76</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F141644%2F5ce38caa-5fd1-4f00-996f-d47744906068.jpg</url>
      <title>DEV Community: Nathan Griffiths</title>
      <link>https://dev.to/griffinator76</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/griffinator76"/>
    <language>en</language>
    <item>
      <title>SQL: ROLLUP Like A Boss</title>
      <dc:creator>Nathan Griffiths</dc:creator>
      <pubDate>Sun, 15 Sep 2019 03:11:11 +0000</pubDate>
      <link>https://dev.to/griffinator76/rollup-like-a-boss-3dkl</link>
      <guid>https://dev.to/griffinator76/rollup-like-a-boss-3dkl</guid>
      <description>&lt;p&gt;So, after reading Helen's great post here: &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I decided it was high time I should contribute a post or two to DEV, so here goes with my first effort - a look at an underused feature of SQL, the ability to add totals and subtotals to results using the ROLLUP and CUBE operators.&lt;/p&gt;

&lt;p&gt;First, a disclaimer. The SQL language is defined by an &lt;a href="https://www.iso.org/standard/63555.html" rel="noopener noreferrer"&gt;ISO standard (9075)&lt;/a&gt;, but as with many "standards" few implementations adhere completely to the standard. Some database systems omit some features, others add their own extensions. That said, what follows is applicable to many of the common database platforms you might use, such as Microsoft SQL Server, Oracle, PostgreSQL and Presto/AWS Athena.&lt;/p&gt;

&lt;h1&gt;
  
  
  SQL GROUP BY 101
&lt;/h1&gt;

&lt;p&gt;A simple &lt;code&gt;SELECT * FROM &amp;lt;table&amp;gt;;&lt;/code&gt; SQL statement will return rows of data from a table in a form that conceptually matches how those rows and columns of data are stored in the table. When designing an &lt;em&gt;application&lt;/em&gt; that works with a database, you'll typically want to work with the data like this, querying rows for display or adding or updating rows with new information.&lt;/p&gt;

&lt;p&gt;However, when using SQL for &lt;em&gt;analytics&lt;/em&gt; we often don't want the information in every single row of a table. We want to aggregate it, for example retrieving the SUM or AVERAGE of the values in one of the columns:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnitsSold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalUnitsSold&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TotalUnitsSold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;550&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Great! So now we have an aggregate value for the whole table. But more realistically we don't want just the total for the table, we want the total broken down for each value in one of the other columns, such as &lt;code&gt;Supplier&lt;/code&gt;. So we do something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnitsSold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalUnitsSold&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supplier&lt;/th&gt;
&lt;th&gt;TotalUnitsSold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wonka's Chocolate Factory&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We've used the &lt;code&gt;GROUP BY&lt;/code&gt; clause of the SQL statement to tell the database to &lt;code&gt;SUM&lt;/code&gt; the values of the &lt;code&gt;UnitsSold&lt;/code&gt; column for each unique value of &lt;code&gt;Supplier&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can extend this to group by two or more columns, so we get a total for each unique combination of values in the grouping columns:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnitsSold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalUnitsSold&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supplier&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;th&gt;TotalUnitsSold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wonka's Chocolate Factory&lt;/td&gt;
&lt;td&gt;Munich&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;New York&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;Paris&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;Peckham&lt;/td&gt;
&lt;td&gt;170&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;Springfield&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;Shelbyville&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nice. Now we've got the basis of a quick report or data extract. &lt;/p&gt;

&lt;p&gt;Hold on though, how many units did "Trotters Independent Trading" sell? Now we've added multiple levels of grouping (Supplier -&amp;gt; City) we have to add those up again to get totals for the higher levels of grouping (e.g. Supplier).&lt;/p&gt;

&lt;p&gt;If you're going to put this query into a reporting or visualisation tool such as Tableau, Power BI or MicroStrategy then your work here is probably done, as those tools can be configured to calculate totals for you when the data gets displayed.&lt;/p&gt;

&lt;p&gt;However, if you're just trying to get some answers quickly out of a database (the boss wants those monthly sales figures stat!) then you're either going to export the data to another tool like Excel to work that out, or, horror of horrors,  manually calculate the totals yourself to append to the results (I've seen it done). If you're a bit more confident you might try creating multiple SQL statements with different levels of grouping an appending them together using &lt;code&gt;UNION ALL&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  ROLLUP, ROLLUP! The GROUP BY circus is in town
&lt;/h1&gt;

&lt;p&gt;Don't panic, SQL is here to save your sanity with the often overlooked ROLLUP and CUBE clauses. Essentially what these SQL statement clauses allow you to do is get the database to do the heavy lifting for you and calculate totals and subtotals in the same set of results.&lt;/p&gt;

&lt;p&gt;Let's go back to our example and say we want to get subtotals for each &lt;code&gt;Supplier&lt;/code&gt; and also an overall total for all orders, so we add &lt;code&gt;ROLLUP&lt;/code&gt; to our &lt;code&gt;GROUP BY&lt;/code&gt; clause:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnitsSold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalUnitsSold&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;ROLLUP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supplier&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;th&gt;TotalUnitsSold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wonka's Chocolate Factory&lt;/td&gt;
&lt;td&gt;Munich&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wonka's Chocolate Factory&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;New York&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;Paris&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;Peckham&lt;/td&gt;
&lt;td&gt;170&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;Springfield&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;Shelbyville&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;550&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice we now have an extra row for each &lt;code&gt;Supplier&lt;/code&gt;, with a &lt;code&gt;NULL&lt;/code&gt; value in the &lt;code&gt;City&lt;/code&gt; column. This represents the sum of all UnitsSold for each Supplier. There's also a row at the bottom that has a &lt;code&gt;NULL&lt;/code&gt; value for both Supplier and City, this is the total UnitsSold for all Suppliers and all Cities (i.e. the total for the whole table) - notice this matches our total from the first simple SUM query we wrote.&lt;/p&gt;

&lt;h1&gt;
  
  
  So that's it?
&lt;/h1&gt;

&lt;p&gt;Well that's great in that we now have our subtotals, but all those &lt;code&gt;NULL&lt;/code&gt; values make this a bit hard to read (and confusing to any non-SQL people you show this to). Luckily &lt;em&gt;most&lt;/em&gt; database platforms also implement a &lt;strong&gt;function&lt;/strong&gt; called GROUPING (sorry Presto/Athena users, you're in the unlucky camp on this one). This function accepts a column name and simply returns 1 (true) or 0 (false) to indicate if the current row contains a subtotal for that column e.g. &lt;code&gt;GROUPING(Supplier)&lt;/code&gt; will return 1 if the row contains a subtotal for Supplier or 0 if it's a regular row.&lt;/p&gt;

&lt;p&gt;One of the things we can do with this GROUPING function is to make our results look at bit clearer by replacing those &lt;code&gt;NULL&lt;/code&gt; values with something a bit more meaningful:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; 
   &lt;span class="k"&gt;CASE&lt;/span&gt; 
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;GROUPING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
         &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'-All Suppliers-'&lt;/span&gt; 
      &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt; 
   &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt;
   &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;CASE&lt;/span&gt; 
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;GROUPING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
         &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'-All Cities-'&lt;/span&gt;
      &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;
   &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnitsSold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalUnitsSold&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;ROLLUP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supplier&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;th&gt;TotalUnitsSold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wonka's Chocolate Factory&lt;/td&gt;
&lt;td&gt;Munich&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wonka's Chocolate Factory&lt;/td&gt;
&lt;td&gt;-All Cities-&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;New York&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;Paris&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;Peckham&lt;/td&gt;
&lt;td&gt;170&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;-All Cities-&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;Springfield&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;Shelbyville&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;-All Cities-&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-All Suppliers-&lt;/td&gt;
&lt;td&gt;-All Cities-&lt;/td&gt;
&lt;td&gt;550&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now that is much easier to read! Time to email the numbers to the boss and nip down to the pub for a celebratory pint.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wait, didn't you mention something about CUBE?
&lt;/h1&gt;

&lt;p&gt;Ah yes, CUBE. To be honest, the use cases for CUBE are rarer than for ROLLUP but it's good to know about it just in case.&lt;/p&gt;

&lt;p&gt;CUBE is basically ROLLUP on steroids - ROLLUP creates subtotals for each sublevel of grouping based on the order of the grouping columns (i.e. in our example there are subtotals for &lt;code&gt;Supplier&lt;/code&gt; and then "all rows", but not &lt;code&gt;City&lt;/code&gt; because that's the "bottom" level of the grouping). &lt;/p&gt;

&lt;p&gt;CUBE on other hand creates subtotals for &lt;em&gt;every combination of values&lt;/em&gt; in the grouping columns. &lt;/p&gt;

&lt;p&gt;How is this useful? Let's look at our example again. Up to now these examples have been assuming that there's a natural hierarchy between Supplier and City i.e. one supplier to many cities (a one-to-many or 1:N relationship), but let's say that actually these are independent attributes of an order so that one Supplier can have many Cities and one City can be related to many Suppliers (a many-to-many or M:N relationship). In that case we don't just want subtotals for Supplier, we want subtotals &lt;em&gt;for each City&lt;/em&gt; as well.&lt;/p&gt;

&lt;p&gt;Simply replace &lt;code&gt;ROLLUP&lt;/code&gt; with &lt;code&gt;CUBE&lt;/code&gt; in our SQL statement and we now get this result:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; 
   &lt;span class="k"&gt;CASE&lt;/span&gt; 
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;GROUPING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
         &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'-All Suppliers-'&lt;/span&gt; 
      &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt; 
   &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;Supplier&lt;/span&gt;
   &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;CASE&lt;/span&gt; 
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;GROUPING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
         &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'-All Cities-'&lt;/span&gt;
      &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;
   &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnitsSold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;TotalUnitsSold&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;CUBE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Supplier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supplier&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;th&gt;TotalUnitsSold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wonka's Chocolate Factory&lt;/td&gt;
&lt;td&gt;Munich&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wonka's Chocolate Factory&lt;/td&gt;
&lt;td&gt;-All Cities-&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;New York&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;Paris&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;Peckham&lt;/td&gt;
&lt;td&gt;170&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trotters Independent Trading&lt;/td&gt;
&lt;td&gt;-All Cities-&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;Springfield&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;Shelbyville&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kwik-E-Mart&lt;/td&gt;
&lt;td&gt;-All Cities-&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-All Suppliers-&lt;/td&gt;
&lt;td&gt;Munich&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-All Suppliers-&lt;/td&gt;
&lt;td&gt;New York&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-All Suppliers-&lt;/td&gt;
&lt;td&gt;Paris&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-All Suppliers-&lt;/td&gt;
&lt;td&gt;Peckham&lt;/td&gt;
&lt;td&gt;170&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-All Suppliers-&lt;/td&gt;
&lt;td&gt;Springfield&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-All Suppliers-&lt;/td&gt;
&lt;td&gt;Shelbyville&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-All Suppliers-&lt;/td&gt;
&lt;td&gt;-All Cities-&lt;/td&gt;
&lt;td&gt;550&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now we have subtotals for each &lt;code&gt;Supplier&lt;/code&gt; and also separate subtotals for each &lt;code&gt;City&lt;/code&gt;, plus the overall total!&lt;/p&gt;

&lt;h1&gt;
  
  
  Fantastic! Now I'm going to add ROLLUP to all my queries!
&lt;/h1&gt;

&lt;p&gt;Woah there cowboy! So as I briefly mentioned, if you're writing a query that's going to be used by a reporting tool like Tableau or whatever then this technique isn't really helpful as those tools will usually do the totalling for you. In fact, this is usually an &lt;a href="https://en.wikipedia.org/wiki/Anti-pattern" rel="noopener noreferrer"&gt;anti-pattern&lt;/a&gt; and not advisable because your reporting tool won't be able to differentiate the subtotal rows from the regular rows and that will make formatting your report a lot harder.&lt;/p&gt;

&lt;p&gt;However, if you're working directly in SQL and just want to generate some data for a quick ad-hoc report or analysis then ROLLUP or CUBE can save you some time and effort in getting the results you need. &lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>cube</category>
      <category>dataanalysis</category>
    </item>
  </channel>
</rss>
