Note: The test database version is MySQL 8.0
If you need scott users to create tables and enter data statements, please refer to:
scott create tables and enter data sql scripts
1. Demand
To create a report that contains subtotals, and then transpose it to make the report easier to read.
For example, it is required to create a report that displays the total salary of each department, department manager, and employees of these managers.
In addition, two subtotals are also returned: the sum of the salaries of the employees of each manager in each department, and the sum of all salaries in the result set (the sum of the department subtotals).
Currently there are the following reports:
±-------±-----±---------+
| deptno | mgr | sal |
±-------±---- -±---------+
| 10 | 7782 | 1300.00 |
| 10 | 7839 | 2450.00 |
| 10 | NULL | 3750.00 |
| 20 | 7566 | 6000.00 |
| 20 | 7788 | 1100.00 |
| 20 | 7839 | 2975.00 |
| 20 | 7902 | 800.00 |
| 20 | NULL | 10875.00 |
| 30 | 7698 | 6550.00 |
| 30 | 7839 | 2850.00 |
| 30 | NULL | 9400.00 |
| NULL | NULL | 24025.00 |
±--- ----±-----±---------+
To provide a more readable report, and hope to convert the above result set into the following format, it will make the meaning of the report more clear:
2. Solution
First, use the rollup of group by to expand the production subtotal, and then perform classic transposition changes (aggregation and CASE expressions) to create the columns required by the report.
Using the GROUPING function, it is easy to determine which values are subtotals (that is, there are no rows under normal circumstances, only rows with rollup added).
+------+---------+----------+---------+-------+
| mgr | dept10 | dept20 | dept30 | total |
+------+---------+----------+---------+-------+
| 7902 | 0.00 | 800.00 | 0.00 | NULL |
| 7839 | 2450.00 | 2975.00 | 2850.00 | NULL |
| 7788 | 0.00 | 1100.00 | 0.00 | NULL |
| 7782 | 1300.00 | 0.00 | 0.00 | NULL |
| 7698 | 0.00 | 0.00 | 6550.00 | NULL |
| 7566 | 0.00 | 6000.00 | 0.00 | NULL |
| NULL | 3750.00 | 10875.00 | 9400.00 | NULL |
+------+---------+----------+---------+-------+
Test Record:
mysql> select mgr,
-> sum(case deptno when 10 then sal else 0 end) dept10,
-> sum(case deptno when 20 then sal else 0 end) dept20,
-> sum(case deptno when 30 then sal else 0 end) dept30,
-> sum(case flag when '11' then sal else null end) total
-> from (
-> select deptno,mgr,sum(sal) sal,
-> cast(grouping(deptno) as char(1))||
-> cast(grouping(mgr) as char(1)) flag
-> from emp
-> where mgr is not null
-> group by deptno,mgr with rollup
-> ) x
-> group by mgr
-> order by mgr desc
-> ;
+------+---------+----------+---------+-------+
| mgr | dept10 | dept20 | dept30 | total |
+------+---------+----------+---------+-------+
| 7902 | 0.00 | 800.00 | 0.00 | NULL |
| 7839 | 2450.00 | 2975.00 | 2850.00 | NULL |
| 7788 | 0.00 | 1100.00 | 0.00 | NULL |
| 7782 | 1300.00 | 0.00 | 0.00 | NULL |
| 7698 | 0.00 | 0.00 | 6550.00 | NULL |
| 7566 | 0.00 | 6000.00 | 0.00 | NULL |
| NULL | 3750.00 | 10875.00 | 9400.00 | NULL |
+------+---------+----------+---------+-------+
7 rows in set, 1 warning (0.00 sec)