Search code examples
mysqlgroup-bymariadbpivotunpivot

mysql - sums per months and years


I have the following demo

CREATE TABLE `tblappointment` (
  `app_id` mediumint(8) UNSIGNED NOT NULL,
  `app_date` date NOT NULL,
  `work_id` smallint(5) UNSIGNED NOT NULL,
  `app_price` double DEFAULT NULL,
  `app_price_paid` double DEFAULT NULL,
  `receipt_id` tinyint(3) UNSIGNED DEFAULT NULL
);

INSERT INTO `tblappointment` (`app_id`, `app_date`, `work_id`, `app_price`, `app_price_paid`, `receipt_id`) VALUES 
("1", "2020-03-01", "21", "100", "50", "1"),
("2", "2020-04-01", "21", "200", "40", "3"),
("4", "2020-06-01",  "2", "500", "70", "1"),
("5", "2020-07-01", "21", "300", "30", "1"),
("6", "2020-08-01", "21", "200", "20", "2"),
("7", "2020-09-01",  "5", "100", "50", "1"),
("8", "2020-10-01",  "6", "200", "30", "2"),
("9", "2020-11-01", "21", "300", "30", "1"),
("10", "2020-12-01", "21", "400", "20", "3"),
("11", "2020-01-01",  "8", "500", "90", "1"),
("12", "2020-02-01", "21", "600", "80", "5"),
("13", "2020-03-01",  "3", "700", "70", "1");

Sample code and schema

sql:

SELECT
YEAR(app_date) AS aYear,
Month(app_date) AS aMonth,
SUM(CASE WHEN work_id = 21 THEN app_price END) AS Work,
SUM(CASE WHEN work_id = 21 THEN app_price_paid END) AS Paid,
SUM(CASE WHEN work_id = 21 THEN app_price END)-SUM(CASE WHEN work_id = 21 THEN app_price_paid END) AS Debt
FROM tblappointment
GROUP BY YEAR(app_date), Month(app_date)
ORDER BY YEAR(app_date), Month(app_date);

Output Now:

YEAR MONTH WORK PAID DEBT
2020   1   numbers here...
2020   2   numbers here...

I would like to have this output:

YEAR   DETAILS   1   2   3   4   5   6   7   8   9   10   11   12
2020   Work     numbers here....
2020   Paid     numbers here....
2020   Debt     numbers here....

Thank you


Solution

  • You can unpivot with union all, then pivot with conditional aggregation:

    select 
        year(app_date) yr,
        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) = 3  then val else 0 end) month_03,
        sum(case when month(app_date) = 4  then val else 0 end) month_04,
        sum(case when month(app_date) = 5  then val else 0 end) month_05,
        sum(case when month(app_date) = 6  then val else 0 end) month_06,
        sum(case when month(app_date) = 7  then val else 0 end) month_07,
        sum(case when month(app_date) = 8  then val else 0 end) month_08,
        sum(case when month(app_date) = 9  then val else 0 end) month_09,
        sum(case when month(app_date) = 10 then val else 0 end) month_10,
        sum(case when month(app_date) = 11 then val else 0 end) month_11,
        sum(case when month(app_date) = 22 then val else 0 end) month_12
    from (
        select app_date, app_price val, 'work' details from tblappointment where work_id = 21
        union all
        select app_date, app_price_paid val, 'paid' details from tblappointment where work_id = 21
        union all
        select app_date, app_price - app_price_paid val, 'debt' details from tblappointment where work_id = 21
    ) t
    group by yr, details