MySQL Pivot: How To Generate a Pivot Table

Do you want to learn how to generate pivoted data or pivot tables in MySQL?

In this article, you'll learn:

  • what the pivot concept is
  • how to generate a pivot table in MySQL
  • how to generate the column headings dynamically

Let's get into the guide.

What is PIVOT?

The concept of a "pivot" is where data in rows is transformed to be shown in columns instead. It's commonly used in Microsoft Excel where you create a Pivot Table to display data differently.

It groups your data based on some values and shows these in columns instead.

Some databases, such as SQL Server, have the PIVOT feature built-in.

However, in MySQL, there is no PIVOT feature or keyword. Fortunately, we can still generate this pivot table output.

Let's see the sample data we'll use, and then the code to generate the pivot table.

 

Sample Data and Expected Output

Let's see some sample data and our expected output to help demonstrate what PIVOT can do.

We've got a product_sales table which has a product name, store location, and number of sales. Each of these are separate columns:

product_name store_location num_sales
Chair North 55
Desk Central 120
Couch Central 78
Chair South 23
Chair South 10
Chair North 98
Desk West 61
Couch North 180
Chair South 14
Desk North 45
Chair North 87
Chair Central 34
Desk South 42
Couch West 58
Couch Central 27
Chair South 91
Chair West 82
Chair North 37
Desk North 68
Couch Central 54
Chair South 81
Desk North 25
Chair North 46
Chair Central 121
Desk South 85
Couch North 43
Desk West 10
Chair North 5
Chair Central 16
Desk South 9
Couch West 22
Couch Central 59
Chair South 76
Chair West 48
Chair North 19
Desk North 3
Couch West 63
Chair South 81
Desk North 85
Chair North 90
Chair Central 47
Desk West 63
Couch North 28

Here's the sample data for this table: mysql_pivot_data.sql

You can download that SQL file to create and populate the tables yourself.

While you're here, if you want a quick reference PDF for the MySQL PIVOT functionality, get the MySQL PIVOT Cheat Sheet here:

Let's say we wanted to see this data with product names on the left and store locations across the top, with the number of sales at each intersection:

product_name North Central South West
Chair 437 218 376 130
Couch 251 218 0 143
Desk 226 120 136 134

We could extract it into an Excel file and create a pivot table.

Or, we could use SQL for this. Let's see how we can do this.

 

MySQL Pivot using CASE

You can use a combination of an aggregate function and the CASE statement to show a pivot table.

How can we write a query to do this?

First, we write a SELECT query that gets the product names:

1SELECT
2product_name
3FROM product_sales;

Then we add in the SUM function as another column:

1SELECT
2product_name,
3SUM()
4FROM product_sales;

For this SUM function, we want to show the sum of the num_sales column, but only where the store_location is North.

We can do this kind of logic using a CASE statement. And the important thing here is that a CASE statement can go inside a function.

So, we put a CASE statement inside the SUM function. We want the CASE statement to say "if the store location is North, then show the number of sales, otherwise show 0".

1SELECT
2product_name,
3SUM(CASE
4  WHEN store_location = 'North' THEN num_sales ELSE 0 END
5) AS north
6FROM product_sales;

In this example we've also put a column alias of "north", so we get that as a column heading instead of a long CASE statement.

Next, we add a GROUP BY clause, because we are showing a column and an aggregate function.

1SELECT
2product_name,
3SUM(CASE
4  WHEN store_location = 'North' THEN num_sales ELSE 0 END
5) AS north
6FROM product_sales
7GROUP BY product_name;

We can run this query, even though there is only one column being calculated, and this is what will be shown:

product_name north
Chair 437
Desk 226
Couch 251

We can now add on the rest of the columns. Add the same SUM and CASE functions but change the store_location to the value you want to check.

The query should look like this:

 1SELECT
 2product_name,
 3SUM(CASE
 4  WHEN store_location = 'North' THEN num_sales ELSE 0 END
 5) AS north,
 6SUM(CASE
 7  WHEN store_location = 'Central' THEN num_sales ELSE 0 END
 8) AS central,
 9SUM(CASE
10  WHEN store_location = 'South' THEN num_sales ELSE 0 END
11) AS south,
12SUM(CASE
13  WHEN store_location = 'West' THEN num_sales ELSE 0 END
14) AS west
15FROM product_sales
16GROUP BY product_name;

When you run this query, you should get these results:

product_name north central south west
Chair 437 218 376 130
Desk 226 120 136 134
Couch 251 218 0 143

We can see the different locations as columns, the different products as rows, and the sum of sales at the intersection of product and location.

That's how you can do a pivot table in MySQL. You can change the columns and rows to use by changing your query, but we've seen the general structure here.

 

Dynamic Pivot Columns

In the example above we generated a pivot table using an aggregate function (SUM) and a CASE statement. The downside to that approach is that we need to know the column headings when we write the query, and the more columns that appear the more code we need to write.

This may be OK for smaller results, but what if you don't know all of the possible values? Or what if the values change?

There is a way to dynamically generate the columns of a PIVOT table output. We use the function called GROUP_CONCAT.

Here's what the structure of the code is:

 1SET @sql = NULL;
 2SELECT GROUP_CONCAT(logic)
 3INTO @sql
 4FROM your_table;
 5 
 6SET @sql = CONCAT('select…', @sql, 'from…');
 7 
 8PREPARE stmt FROM @sql;
 9EXECUTE stmt;
10DEALLOCATE PREPARE stmt;

We use the variable of @sql to store the results of GROUP_CONCAT to avoid characters after the 1024 limit of this function from being cut off.

We then add this value into the rest of the query by concatenating with a SELECT and FROM clause.

We then run it using PREPARE and EXECUTE.

Here's what our real query would look like on the product_sales table.

 1SET @sql = NULL;
 2SELECT
 3GROUP_CONCAT(DISTINCT CONCAT(
 4  'SUM(
 5  CASE WHEN store_location = "', store_location, '" THEN num_sales ELSE 0 END) 
 6  AS ', store_location)
 7)
 8INTO @sql
 9FROM product_sales;
10 
11SET @sql = CONCAT('SELECT product_name, ', @sql, 
12  ' FROM product_sales GROUP BY product_name');
13SELECT @sql;
14 
15PREPARE stmt FROM @sql;
16EXECUTE stmt;
17DEALLOCATE PREPARE stmt;

We use the DISTINCT keyword inside GROUP_CONCAT so we get a unique list of store_locations. Otherwise, we'd get a very long list and our query would show an error.

Now when we run this query, this is what we see:

product_name Central North South West
Chair 218 437 376 130
Desk 120 226 136 134
Couch 218 251 0 143

With this example, your column headers are generated based on the values in the table.

 

Conclusion

While there are no MySQL PIVOT keywords available, you can use the SUM function (or other aggregate functions) as well as the CASE statement to generate a pivot table in MySQL.

You can also use the GROUP_CONCAT function and some procedural code to generate the list of columns dynamically.

While you're here, if you want a quick reference PDF for the MySQL PIVOT functionality, get the MySQL PIVOT Cheat Sheet here:

comments powered by Disqus