MySQL transpose result set with subtotals

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)

Guess you like

Origin blog.csdn.net/u010520724/article/details/114021285