Note: You can probably change the compatibility level. It should not affect anything as long as you are changing the compatibility level to a higher value and you don't have linked servers etc that are relying on this database to be at that specific version. Obviously if you are not sure, don't touch it
Anyway, there are a few ways to do this. This method use UNION, I'm not sure why you said you can't use this method, but this gives exactly what your sample expectation was like.
DECLARE @Temptable TABLE (
Company VARCHAR(5),
ProcessDate DATETIME,
OpExp DECIMAL,
Tax DECIMAL,
Total DECIMAL);
INSERT INTO @TempTable VALUES
('Comp1', getdate(), 1000, 100, 1100),
('Comp1', dateadd(year, -1, getdate()), 2000, 200, 2200),
('Comp1', dateadd(year, -2, getdate()), 3000, 300, 3300);
SELECT * FROM @TempTable
DECLARE @ReportStartYear int = 2017
SELECT
t.Company
, 'OpExp' as Val
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -2 THEN OpExp ELSE 0 END) AS ColA
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -1 THEN OpExp ELSE 0 END) AS ColB
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear THEN OpExp ELSE 0 END) AS ColC
, @ReportStartYear - 2 as ColACaption
, @ReportStartYear - 1 as ColBCaption
, @ReportStartYear as ColCCaption
FROM @Temptable t
GROUP BY t.Company
UNION ALL
SELECT
t.Company
, 'Tax' as Val
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -2 THEN Tax ELSE 0 END) AS ColA
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -1 THEN Tax ELSE 0 END) AS ColB
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear THEN Tax ELSE 0 END) AS ColC
, @ReportStartYear - 2 as ColACaption
, @ReportStartYear - 1 as ColBCaption
, @ReportStartYear as ColCCaption
FROM @Temptable t
GROUP BY t.Company
UNION ALL
SELECT
t.Company
, 'Total' as Val
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -2 THEN Total ELSE 0 END) AS ColA
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -1 THEN Total ELSE 0 END) AS ColB
, SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear THEN Total ELSE 0 END) AS ColC
, @ReportStartYear - 2 as ColACaption
, @ReportStartYear - 1 as ColBCaption
, @ReportStartYear as ColCCaption
FROM @Temptable t
GROUP BY t.Company
This returns the following
Company Val ColA ColB ColC ColACaption ColBCaption ColCCaption
Comp1 OpExp 3000 2000 1000 2015 2016 2017
Comp1 Tax 300 200 100 2015 2016 2017
Comp1 Total 3300 2200 1100 2015 2016 2017
In your report, you can set your column headers to be =FIRST(Fields!ColACaption.Value)
etc so you don't have to worry about the column names being dynamic.
This method works if you know how many columns you will return.
HOWEVER If might be easier to just do this in SSRS. Create a matrix, set the column group to be an expression that returns the YEAR of the ProcessDate column, then add a row within the detail group for each of your value types (OpExp, Tax & Total) and that should give you what you want also with no need to change any SQL.