MySQL - 每天旋转 table

MySQL - Pivot table per day

考虑以下架构:

CREATE TABLE IF NOT EXISTS `tblappointment` (
  `app_id` int(6),
  `app_date` date,
  `app_price` int(6),
  `app_price_in` int(6),
  `app_price_out` int(6),
  PRIMARY KEY (`app_id`)
) DEFAULT CHARSET=utf8;

INSERT INTO `tblappointment` (`app_id`, `app_date`, `app_price`, `app_price_in`, `app_price_out`) VALUES
  ('1', '2021/03/20', '50', '80', '30'),
  ('2', '2021/05/10', '30', '20', '50'),
  ('3', '2021/01/14', '20', '60', '10'),
  ('4', '2021/04/05', '20', '20', '20'),
  ('5', '2020/07/08', '30', '70', '10'),
  ('6', '2019/08/28', '40', '80', '40'),
  ('7', '2020/12/11', '50', '10', '60'),
  ('8', '2018/10/19', '10', '20', '30'),
  ('9', '2019/01/10', '20', '30', '20'),
  ('10', '2021/12/13', '10', '20', '20');

我有以下 MySQL 查询,我正在获取每月(列)和每年(行)的总和。

我现在的输出是这样的:

+------+-----+-----+-----+-----+-----+-----+-------+
| Year | 1   | 2   | 3   | ... | 11  | 12  | Total |
+------+-----+-----+-----+-----+-----+-----+-------+
| 2021 | 200 | 250 | 150 |     | 100 | 200 | 1300  |
+------+-----+-----+-----+-----+-----+-----+-------+
| 2020 | 100 | 150 | 200 |     | 100 | 100 | 1700  |
+------+-----+-----+-----+-----+-----+-----+-------+

我想要每天(列)和每年、每月(行)。

希望输出看起来像这样:

+------+--------+----+----+----+-----+----+----+-------+
| Year | Months | 1  | 2  | 3  | ... | 30 | 31 | Total |
+------+--------+----+----+----+-----+----+----+-------+
| 2021 | 2      | 50 | 20 | 10 |     | 20 | 10 | 350   |
+------+--------+----+----+----+-----+----+----+-------+
| 2021 | 1      | 10 | 0  | 20 |     | 10 | 20 | 130   |
+------+--------+----+----+----+-----+----+----+-------+
| 2020 | 12     | 20 | 10 | 20 |     | 10 | 10 | 240   |
+------+--------+----+----+----+-----+----+----+-------+

我的 MySQL 代码是:

select 
    y.yr,
    d.details,
    sum(case when month(app_date) = 1  then val else 0 end) month_01,
    sum(case when month(app_date) = 2  then val else 0 end) month_02,
    ...
    sum(case when month(app_date) = 12 then val else 0 end) month_12,
    sum(case when month(app_date) > 0  then val else 0 end) total
FROM (
    SELECT '101' dorder, 'balance' details UNION ALL 
    SELECT '102' dorder, 'in' details UNION ALL
    SELECT '103' dorder, 'out' details
) d cross join (
    SELECT distinct year(app_date) yr
    FROM tblappointment 
) y    
left join (  
        select app_date, COALESCE(app_price, 0) val, 'balance' details from tblappointment 
    union all
        select app_date, COALESCE(app_price_in, 0) val, 'in' details from tblappointment 
    union all
        select app_date, COALESCE(app_price_out, 0) val, 'out' details from tblappointment 
) t on year(t.app_date) = y.yr and t.details = d.details
group by y.yr, d.details
order by y.yr desc, d.dorder;

我的构建模式和用于测试的示例数据:

Build Schema Demo Page

经过一些测试发现:

    select 
    y.yr,
    y.mth,
    d.details,
    sum(case when day(app_date) = 1  then val else 0 end) day_01,
    sum(case when day(app_date) = 2  then val else 0 end) day_02,
    sum(case when day(app_date) = 3  then val else 0 end) day_03,
    ...
    sum(case when day(app_date) = 31 then val else 0 end) day_31,
    sum(case when day(app_date) > 0  then val else 0 end) total
FROM (
    SELECT '101' dorder, 'balance' details UNION ALL 
    SELECT '102' dorder, 'in' details UNION ALL
    SELECT '103' dorder, 'out' details
) d cross join (
    SELECT distinct year(app_date) yr, month(app_date) mth
    FROM tblappointment 
) y    
left join (  
        select app_date, COALESCE(app_price, 0) val, 'balance' details from tblappointment 
    union all
        select app_date, COALESCE(app_price_in, 0) val, 'in' details from tblappointment 
    union all
        select app_date, COALESCE(app_price_out, 0) val, 'out' details from tblappointment 
) t on year(t.app_date) = y.yr and month(t.app_date) = y.mth and t.details = d.details
group by y.yr, y.mth, d.details
order by y.yr desc, y.mth desc, d.dorder;