In case the table is named Travel, you could do it like this:
SELECT
ID,
Year,
Site,
STRING_AGG(Destination, ', ') AS Destination
INTO #Destination
FROM
(
SELECT DISTINCT
t1.ID,
t1.Year,
t1.Site,
t2.Site AS Destination
FROM Travel t1
INNER JOIN Travel t2 ON t2.Year = t1.Year + 1 AND t2.ID = t1.ID
) AS Dst
GROUP BY
ID,
Year,
Site
SELECT
t.*,
d.Destination
FROM Travel t
LEFT JOIN #Destination d ON t.ID = d.ID AND t.Site = d.Site AND t.Year = d.Year
Explanation:
For every ID, Year and Site take all sites (Destinatins) in the next year, without repeating data.
SELECT DISTINCT
t1.ID,
t1.Year,
t1.Site,
t2.Site AS Destination
FROM Travel t1
INNER JOIN Travel t2 ON t2.Year = t1.Year + 1 AND t2.ID = t1.ID
Store that data into temporary table #Destination which contains ID, Year, Site and all destinations in a single string, separated by ,.
SELECT
ID,
Year,
Site,
STRING_AGG(Destination, ', ') AS Destination
INTO #Destination
FROM
(
-- previous code
) AS Dst
GROUP BY
ID,
Year,
Site
Finally, take destination for each site.
SELECT
t.*,
d.Destination
FROM Travel t
LEFT JOIN #Destination d ON t.ID = d.ID AND t.Site = d.Site AND t.Year = d.Year
Edit: In case of SQL Server 2016 or older.
SELECT DISTINCT
ID,
Year,
Site,
SUBSTRING((SELECT ', ' + Site FROM Travel WHERE Year = t.Year + 1 AND ID = t.ID FOR XML PATH('')), 3, 1000) AS Destination
INTO #Destination
FROM Travel t
SELECT
t.*,
d.Destination
FROM Travel t
LEFT JOIN #Destination d ON t.ID = d.ID AND t.Site = d.Site AND t.Year = d.Year
Explanation:
This example is using XML PATH. STUFF is omitted as it can cause slowdown in performance. Temporary table #Destination is simpler to create. Main change is:
SUBSTRING((SELECT ', ' + Site FROM Travel WHERE Year = t.Year + 1 AND ID = t.ID FOR XML PATH('')), 3, 1000) AS Destination
1.
SELECT ', ' + Site FROM Travel WHERE Year = t.Year + 1 AND ID = t.ID
This line of code takes all Sites for given ID and next Year.
2.
SELECT ', ' + Site FROM Travel WHERE Year = t.Year + 1 AND ID = t.ID FOR XML PATH('')
This line adds FOR XML PATH(''). It creates a single string containing Sites for given ID and next Year. In front of every Site are , and empty space.
3.
SUBSTRING((SELECT ', ' + Site FROM Travel WHERE Year = t.Year + 1 AND ID = t.ID FOR XML PATH('')), 3, 1000) AS Destination
This line of code adds SUBSTRING( before and , 3, 1000) after line in previous step, and names it Destination. Purpose of SUBSTRING is to remove first , and empty space, because they exist in front of every Site. It does so by removing all characters before the third one (so first - ,, and second - empty space) and all characters after the 1000th character. It can be any number instead of 1000 as long as it is bigger than length of Destination string.