First, I try to resist the atavistic impulse to sort a data set by descending order as a means of looking ahead, especially if you're going to re-sort by ascending order - very expensive for large data sets.
You want to flag the last non-missing record for each by group:
data v_need / view=v_need;
set one;
by id test visit ptnum;
where val^=.;
if last.ptnum;
flag='Y';
run;
data two;
merge one v_need;
by id test visit ptnum date;
run;
** This looks like two passes through the data, but V_NEED is a data set view, not a data set file. That means it is not written to disk, and is activated until called in the DATA TWO step - at which point it is streamed to the data two step. As a result, in data two, there wlil be two simultaneous streams of input from dataset ONE. In turn that means that ONE is physically being accessed only once, because the disk input blocks for one stream will be cached in memory and used by the other stream, all thanks to your operating system.
... View more