Преобразование данных, ориентированных на столбцы, в данные, ориентированные на строки - PullRequest
0 голосов
/ 10 февраля 2020

У меня есть данные по этой схеме в моей таблице (поле AVG_TEAM - AVG (AVG_OK), где TEAM_ID = TEAM_ID в строке и MONTH = MONTH в строке )

DRIVER_ID  | MONTH  | TEAM_ID  | AVG_OK  |  AVG_TEAM
----------------------------------------------------
     005     201901     XXXX      81          84
     005     201902     XXXX      84          82
     005     201903     XXXX      81          80
     005     201904     ZZZZ      84          75
     070     201901     RRRR      77          80
     070     201902     RRRR      80          80

etc    

Некоторые люди хотели бы следить за развитием каждого водителя в течение месяца. Ожидаемая схема будет:

DRIVER_ID | TEAM_ID  | AVG_OK_MONTH1  |  AVG_OK_MONTH2  |  AVG_OK_MONTH3  |   ...  |  AVG_OK_MONTH12  | GLOBAL_AVG  |  TEAM_GLOBAL_AVG
    005       XXXX          81                84               81             ...          NULL               82            ?
    070       RRRR          77                80               NULL           ...          NULL              78.5           ?
etc

Как вы, вероятно, заметили, в этом подходе уже есть большой недостаток, поскольку TEAM_ID может меняться с месяцем, и поэтому поле AVG_TEAM нельзя использовать для простого вычисления Поле TEAM_GLOBAL_AVG

Но, допустим, мы убрали этот недостаток и решили, что TEAM_ID не изменится. Я не вижу простого подхода к преобразованию первой схемы в другую, либо с SQL, либо с PHP (никогда не делал этого).

У меня есть несколько очень уродливых решений, использующих массивы в PHP но должны быть лучшие и более простые способы? Любое понимание приветствуется.

1 Ответ

1 голос
/ 10 февраля 2020

Я думаю, что вы можете использовать условную агрегацию. Предполагая, что month является датой:

select driver_id,
       max(case when month(month) = 1 then avg_ok end) as avg_ok_1,
       max(case when month(month) = 2 then avg_ok end) as avg_ok_2,
       max(case when month(month) = 3 then avg_ok end) as avg_ok_3,
       max(case when month(month) = 4 then avg_ok end) as avg_ok_4
from t
where month >= '2019-01-01' and month < '2020-01-01'
group by driver_id;

В противном случае вы можете сделать что-то похожее с функциями строки или даты:

select driver_id,
       max(case when right(month, 2) = '01' then avg_ok end) as avg_ok_1,
       max(case when right(month, 2) = '02' then avg_ok end) as avg_ok_2,
       max(case when right(month, 2) = '03' then avg_ok end) as avg_ok_3,
       max(case when right(month, 2) = '04' then avg_ok end) as avg_ok_4
from t
where month >= '201901' and month < '202001'
group by driver_id;
...