Я бы просто сделал обычный выбор с GROUP BY за месяц, и ваш дескриптор пользовательского интерфейса отображал бы его в виде 12 столбцов в поперечнике. Если вам действительно нужно это сделать, тогда это должно сработать:
SELECT
D.name,
AVG(CASE WHEN MONTH(V.visit_date) = 1 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 2 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 3 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 4 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 5 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 6 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 7 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 8 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 9 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 10 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 11 THEN V.cost ELSE NULL END),
AVG(CASE WHEN MONTH(V.visit_date) = 12 THEN V.cost ELSE NULL END)
FROM
Doctors D
INNER JOIN Visits V ON
V.id_doc = D.id AND
V.visit_date BETWEEN '2009-01-01' AND '2009-12-31'
GROUP BY
D.name
ORDER BY
D.name
Возможно, вам придется изменить функции даты в зависимости от вашей СУБД. Кроме того, вам, возможно, придется поэкспериментировать с крайними случаями - если у ваших дат есть компонент времени, он не будет ловить строки 12/31.
Наконец, я не знаю, если это изменится между RDBMS, и я не могу сейчас тестировать, но если AVG считает NULL как стоимость 0 вместо их дисконтирования, вам, возможно, придется сделать свое собственное усреднение - SUM (CASE ... стоимость ... 0) / СУММА (СЛУЧАЙ ... 1 ... 0). Я надеюсь, что это имеет смысл.