4.4 Accumulating Totals & Subtotals (RETAIN & Sum Statement)
Key Takeaways
- At the beginning of each DATA step execution loop, SAS automatically re-initializes all newly created variables in the PDV to missing values.
- The RETAIN statement overrides default re-initialization, instructing SAS to preserve a variable's stored value in the PDV across DATA step iterations.
- A Sum Statement (variable + expression;) implicitly retains the target variable, initializes its value to 0 before the first iteration, and automatically ignores missing values in the expression.
- Explicit accumulation (Total = Total + Amount; with RETAIN Total 0;) will convert Total to missing (.) if Amount is missing, disrupting calculations for all subsequent rows.
- BY-group processing combined with FIRST.variable and LAST.variable automatic temporary variables enables resetting accumulators at group boundaries and writing subtotal rows.
4.4 Accumulating Totals & Subtotals (RETAIN & Sum Statement)
Quick Answer: By default, at the start of each DATA step iteration, SAS resets all non-dataset variables in the Program Data Vector (PDV) to missing (
.for numeric, blank for character). To accumulate running totals or preserve values across rows, you must prevent SAS from re-initializing variables. You can achieve this using either an explicitRETAINstatement or an implicit Sum Statement (variable + expression;).
Default DATA Step Re-initialization
To understand accumulation, you must understand the PDV lifecycle:
- Input Variables (read via
SET,MERGE,MODIFY, orINPUT): Retain their values as new rows are read. - Created Variables (computed via assignment statements): Reset to missing at the top of every DATA step iteration loop.
/* FAILS TO ACCUMULATE: RunningTotal resets to missing at the start of every row! */
data work.bad_accumulator;
set work.transactions;
RunningTotal = RunningTotal + Amount; /* Always evaluates to missing (.) */
run;
In work.bad_accumulator, RunningTotal starts as missing (.). On row 1, . + Amount evaluates to missing. On row 2, SAS resets RunningTotal back to missing before executing the assignment, failing to accumulate.
The RETAIN Statement
The RETAIN statement is a compile-time directive that tells SAS not to set specified variables to missing at the beginning of each execution iteration. Instead, variables keep their previous values until new values are assigned.
Syntax
RETAIN variable-1 <initial-value-1> ... variable-n <initial-value-n>;
- Without Initial Value: Numeric variables initialize to numeric missing (
.), and character variables initialize to blank (' '). - With Initial Value: The variable is set to the specified constant before the first observation is processed.
data work.retained_total;
set work.transactions;
/* Preserve RunningTotal across rows, starting at 0 */
retain RunningTotal 0;
/* Explicit accumulator assignment using SUM function to ignore missing Amount values */
RunningTotal = sum(RunningTotal, Amount);
run;
The SAS Sum Statement
SAS provides a special abbreviated syntax designed specifically for accumulation called the Sum Statement:
variable + expression;
CRITICAL EXAM CONCEPT: Notice there is no equal sign (
=) in a Sum Statement!Total + Sales;is a Sum Statement, whereasTotal = Total + Sales;is an assignment statement.
The Four Implicit Behaviors of a Sum Statement
When SAS compiles a Sum Statement (variable + expression;), it automatically applies four rules:
- Implicit Creation: Creates
variableas a numeric variable if it does not already exist. - Implicit Initial Value: Sets
variableinitial value to0before processing the first observation. - Implicit RETAIN: Retains
variableacross all DATA step iterations. - Missing Value Immunity: Adds the value of
expressiontovariable, treating missing values inexpressionas0(ignoring missing values).
data work.sum_statement_demo;
set work.transactions;
/* Replaces RETAIN, assignment, and SUM function in one concise statement */
RunningTotal + Amount;
run;
Comparison: Explicit Retention vs. Sum Statement
| Feature / Behavior | Explicit Assignment (Total = Total + Amount; with RETAIN Total 0;) | SAS Sum Statement (Total + Amount;) |
|---|---|---|
| Syntax | Requires RETAIN statement + Total = Total + Amount; | Total + Amount; (No RETAIN, no =) |
| Default Initial Value | Missing (.) unless explicitly specified in RETAIN Total 0; | Automatically initialized to 0 |
Handling Missing Amount | Evaluates to missing (.), corrupting Total for all subsequent rows! | Treats missing Amount as 0, preserving running total |
| SAS Log Behavior on Missing | Writes diagnostic note: Missing values were generated... | Silent execution; no log warnings |
| Recommended Use Case | When custom initial values (e.g., 100) or complex logic are needed | Standard running totals and BY-group subtotals |
BY-Group Subtotal Accumulation (FIRST. and LAST.)
In business reporting, you often need to calculate running totals per category (e.g., total sales per Department or Customer). This requires combining BY group processing with accumulation logic.
Automatic Variables: FIRST.variable and LAST.variable
When a BY statement is included in a DATA step, SAS creates two temporary automatic numeric variables for each BY variable:
FIRST.variable: Equals 1 on the first observation of a BY group, and 0 for all subsequent observations in that group.LAST.variable: Equals 1 on the last observation of a BY group, and 0 for all other observations in that group.
Note: Input datasets MUST be pre-sorted by the BY variable (using
PROC SORT) before executing BY-group processing in a DATA step.
Subtotal Reset Pattern
/* Step 1: Pre-sort input data */
proc sort data=sashelp.shoes out=work.shoes_sorted;
by Region;
run;
/* Step 2: Accumulate subtotals per Region */
data work.region_subtotals;
set work.shoes_sorted;
by Region;
/* Reset accumulator on the FIRST row of each Region group */
if First.Region then RegionSales = 0;
/* Accumulate sales for rows within the Region */
RegionSales + Sales;
/* Subset: Output ONLY the LAST row of each Region group containing final subtotal */
if Last.Region;
keep Region RegionSales;
run;
Step-by-Step Execution Trace
- When
Regionchanges to'Asia',First.Regionis 1. SAS setsRegionSales = 0. RegionSales + Sales;adds the current row's sales.- Intermediate rows (
First.Region = 0,Last.Region = 0) accumulate sales without outputting becauseif Last.Region;filters them out. - On the final row of
'Asia',Last.Regionis 1. The subsettingIFevaluates to true, and SAS outputs the summary record containingRegionand the accumulatedRegionSalessubtotal.
What are the four implicit characteristics of a SAS Sum Statement (Count + 1; or Total + Sales;)?
Consider the following DATA step:
What is the role of data work.summary;
set work.sales;
by Department;
if First.Department then SalesTotal = 0;
SalesTotal + Revenue;
if Last.Department;
run;
if Last.Department; in this program?
A programmer uses explicit assignment to calculate a running total:
If data work.calc;
set work.transactions;
retain Total 0;
Total = Total + Amount;
run;
Amount is missing (.) on observation 3, what will be the value of Total for observation 3 and all subsequent observations?
What is the initial stored value of a variable specified in a RETAIN statement if no explicit initial value is provided (e.g., retain Count;)?