Having two levels of heading (plan name > years) is a display issue, not a query issue. However, you can flatten the header by merging the planname and planyear columns in the PIVOT as follows. The search term for this technique is "dynamic pivot".
SQL Fiddle
create table #tmp (
BrokerCode int,
PlanYear int,
PlanName char(3),
Fresh decimal(10,4));
insert #tmp select
106 , 3 , 'SLP' , 0.00 union all select
106 , 3 , 'MLP' , 1140.00 union all select
106 , 5 , 'MLP' , 570.00 union all select
205 , 4 , 'SLP' , 450.00;
declare @sql nvarchar(max);
select @sql = isnull(@sql+',','') +
quotename(PlanName+'-'+right(PlanYear,10))
from (select distinct PlanName from #tmp) a
cross join (select distinct PlanYear from #tmp) b
order by PlanName, PlanYear;
set @sql = '
SELECT *
FROM
(
SELECT PlanName+''-''+right(PlanYear,10) [PlanYear],
[BrokerCode], [Fresh]
FROM #tmp
) AS source
PIVOT
(
sum([Fresh])
FOR [PlanYear] IN ('+@sql+')
) as pvt';
exec(@sql);
Results:
| BROKERCODE | MLP-3 | MLP-4 | MLP-5 | SLP-3 | SLP-4 | SLP-5 |
--------------------------------------------------------------------
| 106 | 1140 | (null) | 570 | 0 | (null) | (null) |
| 205 | (null) | (null) | (null) | (null) | 450 | (null) |
If you really wanted the output at the end of your question, then the below variation will do.
declare @sql nvarchar(max);
select @sql = isnull(@sql+',','') +
quotename(right(PlanYear,10))
from (select distinct PlanYear from #tmp) b
order by PlanYear;
set @sql = '
SELECT *
FROM
(
SELECT [PlanYear], [BrokerCode], [Fresh]
FROM #tmp
) AS source
PIVOT
(
sum([Fresh])
FOR [PlanYear] IN ('+@sql+')
) as pvt';
-----------------------------------------
| BROKERCODE | 3 | 4 | 5 |
-----------------------------------------
| 106 | 1140 | (null) | 570 |
| 205 | (null) | 450 | (null) |