BY-Group Processing
Prerequisites: Combining data sets with SET and MERGE
When a DATA step reads sorted data with a BY statement, SAS creates two
temporary flags for each BY variable:
FIRST.var— 1 on the first row of each group.LAST.var— 1 on the last row of each group.
Combined with variables that keep their values between rows, they let you compute per-group results in a single pass.
RETAIN and the sum statement
Normally, variables you create are reset to missing at the start of each iteration. Two ways to keep them:
retain total 0;— keeptotalacross rows, starting at 0.total + amount;— a sum statement: it retainstotal, starts it at 0, and treats a missingamountas 0.
data running;
input day amount;
total + amount;
datalines;
1 10
2 .
3 25
;
run;
proc print data=running noobs;
run;
day amount total
1 10 10
2 . 10
3 25 35
total = total + amount; would not work: total would be reset to
missing each row.
Per-group summaries
proc sort data=sashelp.class out=cls;
by sex;
run;
data by_sex;
set cls;
by sex;
if first.sex then do;
n = 0;
total = 0;
end;
n + 1;
total + weight;
if last.sex then do;
avg = total / n;
output;
end;
keep sex n total avg;
format avg 6.2;
run;
proc print data=by_sex noobs;
run;
Sex n total avg
F 9 811.0 90.11
M 10 1089.5 108.95
- On the first row of a group, reset the counters.
- On every row, accumulate.
- On the last row, compute and
OUTPUTone summary row.
Counting within groups
Number the rows within each group — for example, to keep each patient's first visit:
data visits;
input patient $ visit_date :date9.;
format visit_date date9.;
datalines;
P1 03JAN2024
P1 17JAN2024
P2 05JAN2024
P1 30JAN2024
P2 20FEB2024
;
run;
proc sort data=visits;
by patient visit_date;
run;
data numbered;
set visits;
by patient;
if first.patient then visit_no = 0;
visit_no + 1;
run;
proc print data=numbered noobs;
run;
patient visit_date visit_no
P1 03JAN2024 1
P1 17JAN2024 2
P1 30JAN2024 3
P2 05JAN2024 1
P2 20FEB2024 2
Add if first.patient; to keep only first visits, or if last.patient;
for the latest.
Common mistakes
- Forgetting to sort —
ERROR: BY variables are not properly sorted on data set WORK.VISITS. - With
by a b;,first.bis also 1 wheneverachanges — nested groups behave the way you'd hope.
Practice
Using cls from above, find the tallest student of each sex.
Show solution
proc sort data=sashelp.class out=cls2;
by sex height;
run;
data tallest;
set cls2;
by sex;
if last.sex;
keep sex name height;
run;
proc print data=tallest noobs;
run;
Name Sex Height
Mary F 66.5
Philip M 72.0
Sorting by height inside sex puts the tallest last in each group.