I'd suggest to use conditional aggregation:
DECLARE @tbl TABLE(ID INT, [year] INT, reading INT, writing INT, spelling INT);
INSERT INTO @tbl VALUES
(33087,7,625,620,686)
,(33087,8,544,560,541)
,(33205,7,559,572,497)
,(33205,8,599,560,612)
,(33902,7,500,484,464)
,(33902,8,607,560,686);
--the query:
SELECT t.ID
,MAX(CASE WHEN t.[year]=7 THEN t.[year] END) AS year_1
,MAX(CASE WHEN t.[year]=7 THEN t.reading END) AS reading_1
,MAX(CASE WHEN t.[year]=7 THEN t.writing END) AS writing_1
,MAX(CASE WHEN t.[year]=7 THEN t.spelling END) AS spelling_1
,MAX(CASE WHEN t.[year]=8 THEN t.[year] END) AS year_2
,MAX(CASE WHEN t.[year]=8 THEN t.reading END) AS reading_2
,MAX(CASE WHEN t.[year]=8 THEN t.writing END) AS writing_2
,MAX(CASE WHEN t.[year]=8 THEN t.spelling END) AS spellingg_
--add more blocks if needed
FROM @tbl t
GROUP BY t.ID;
PIVOT
is limited to one single column. In your case you want to "pivot" several columns at once. This approach offers most control over the way you compute/aggregate your data, if there is more than one row per ID and year.
Another advantage: This is quite easy to create dynamically. In this case you would have to look into your data, find the occuring years and create one block per year. Then you execute the statement.
Another approach was conditional joining:
WITH IDsOnly AS
(
SELECT t.ID
FROM @tbl t
GROUP BY t.ID
)
SELECT IDsOnly.ID
,A.[year] AS year_1,A.reading AS reading_1,A.writing AS writing_1,A.spelling AS spelling_1
,B.[year] AS year_2,B.reading AS reading_2,B.writing AS writing_2,B.spelling AS spelling_2
FROM IDsOnly
LEFT JOIN(SELECT * FROM @tbl t7 WHERE t7.[year]=7) AS A ON IDsOnly.ID=A.ID
LEFT JOIN(SELECT * FROM @tbl t7 WHERE t7.[year]=8) AS B ON IDsOnly.ID=B.ID;
--Add more joins if needed...