Есть два способа сделать это:
Создать декартову структуру в вашем запросе, используя различные значения группировки строк и столбцов.
SELECT
C.MonthStarting
,R.Category
,D.InstanceCount
FROM ( -- column values
SELECT DISTINCT MonthStarting
FROM Calendar
WHERE MonthStarting BETWEEN @StartDate AND @EndDate
) AS AS C
JOIN ( -- row values
SELECT DISTINCT Category
FROM SomeRelevantTables
) AS R
ON 1 = 1 -- intentional cartesian product
LEFT JOIN (
SELECT
Category
,MonthStarting
,COUNT(1) AS InstanceCount
FROM SomeRelevantTables
GROUP BY
Category
,MonthStarting
) AS D
ON C.MonthStarting = D.MonthStarting
AND R.Category = D.Category
Или вы можете повернуть столбцы взапрос вместо макета и отображения данных в виде таблицы вместо матрицы.
SELECT
T.Category
,SUM(CASE WHEN C.RowNumberAsc = 1 THEN 1 END) AS Column1
,SUM(CASE WHEN C.RowNumberAsc = 2 THEN 1 END) AS Column2
,SUM(CASE WHEN C.RowNumberAsc = 3 THEN 1 END) AS Column3
,SUM(CASE WHEN C.RowNumberAsc = 4 THEN 1 END) AS Column4
FROM SomeRelevantTables AS T
JOIN (
SELECT
C.*
,ROW_NUMBER()OVER(PARTITION BY MonthStarting) AS RowNumberAsc
FROM (
SELECT DISTINCT MonthStarting
FROM Calendar
WHERE MonthStarting BETWEEN @StartDate AND @EndDate
) AS C
) AS C
ON T.MonthStarting = C.MonthStarting
GROUP BY
T.Category