You have data sorted by ID, and you want all records for any ID with 3 or more records.
Although it is a common technique, you don't really have to count records for an ID. The counting strategy means you have to read every ID group twice. The first time to generate a count, and the second time to re-read the id group and output records for ID's with counts of 3 or more. That's one of the solutions offered by @FreelanceReinh.
Assuming you don't actually need to output a counter variable, you can just merge a record with the id of the second-following record. Whenever the record-in-hand is the beginning of an ID, and the 2nd trailing record has a matching ID, you know you are at the start of an ID group that meets you condition. In that case, just set variable _KEEPFLAG to "Y", (and let _KEEPFLAG retain its value throughout the ID group), and output only those records with _KEEPFLAG='Y'.
data want (drop=_:);
set have (keep=id);
by id;
merge have
have (firstobs=3 keep=id rename=(id=_nxt_id2));
retain _keepflag;
if first.id=1 then do;
if _nxt_id2=id then _keepflag='Y';
else _keepflag='N';
end;
if _keepflag='Y';
run;
BTW, you don't really need the extra "set have; by id;" statements. You can also detect the start of an ID group using a test on LAG(ID) vs current ID, as in:
data want (drop=_:);
merge have
have (firstobs=3 keep=id rename=(id=_nxt_id2));
retain _keepflag;
if id ^= lag(id) then do;
if _nxt_id2=id then _keepflag='Y';
else _keepflag='N';
end;
if _keepflag='Y';
run;
... View more