Here is an answer which I think will work for all cases, although I don't know how efficient it is:
I'm starting with a data set with a few more observations added to show how the code can handle more difficult cases.
data have;
input year id2 id1;
datalines;
2010 1 201
2010 1 202
2010 2 203
2011 3 202
2011 4 203
2011 5 204
2011 6 205
2011 6 203
2011 7 206
;
run;
First I create a character variable called "links" which has id1 and id2 in it.
data links;
length links $ 20;
set have;
id2t = compress("id2_"||put(id2, 5.));
id1t = compress("id1_"||put(id1, 7.));
links = id2t||" "||id1t;
run;
Then I assign each value of "links" to an element in temporary array "agroup". Next I take each element in agroup which has been assigned a value from "links" and compare it to each subsequent value of agroup. If the values have any id1s or id2s in common, then I concatenate the two together, or, if a value doesn't match any other values, then I put it as the next value of bgroup. Then I go back to the next value of agroup and do the same, repeating the process until I have gone through all the values. At the end there is one value of bgroup for each group, and each value has the id1s and ids2 from all the members. Finally I match up these groups with the original data set to get group numbers.
data final;
array agroup[100] $200. _temporary_;
array bgroup[100] $200. _temporary_;
do until (eof);
set links end=eof;
a+1;
agroup[a] = links;
end;
do k = 1 to a;
found = 0;
do i = k+1 to a until (found=1);
do j = 1 to countw(agroup[k]) until (found = 1);
if find(agroup[i], scan(agroup[k], j)) > 0 then do;
found = 1;
agroup[i] = strip(strip(agroup[k])||' '||strip(agroup[i]));
end;
end;
end;
if found = 0 then do;
b+1;
bgroup[b] = agroup[k];
end;
end;
do until (eof2);
set links end=eof2;
do i = 1 to b;
if find(bgroup[i], id2t)+find(bgroup[i], id1t) > 0 then id3 = i;
end;
output;
end;
keep year id2 id1 id3;
run;