Try using the FIRSTOBS and OBS options in the set statement. FIRSTOBS has SAS go to the record # that you want. OBS is the total number of records to be read. Eventhough you want the last 10 you still need to read all of them but ignore all but the last 10, so have set OBS= your N # of records. See my example below.
1) reads a total of 11 observations, 1 first, then 10 second
set indata (obs=1) nobs=N;
first = N-9;
%put first = &first ;
%put last = &last ;
set indata (firstobs=&first obs=&last);
2) reads a total of 10 observations
do i = (N-9) to N;
set indata nobs=N point=i;
as it is coming from a base SAS data set, you can vary Oliver's program, just a little to obtain top performance from v.large tables.[pre]
DATA last10 ;
do _n_ = total_n - 9 to totalN ;
SET dataset NOBS=totalN POINT=_n_ ;
RUN ; [/pre]
Using POINT access ensures you read only the last 10 rows, even if your table has a billion rows.
Total_n is acquired at compile time, even before the SET statement is executed.
Of course, that information may not be available if the input dataset does not support the "point access" that base SAS tables allows. Examples of that limitation occur with data views and non-SAS tables like tables accessed through a SAS/Access to rdbms.
Thanks and Sorry for wasting bandwidth repeating your solution (which I had missed).
As to _n_:
I find _N_ convenient because it is not added to the output dataset, so I need no drop statement (for variable I in your example), nor do I need to take care to select a variable name for the loop control that is not already on the input data set.