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.
Last updated: August 2026

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 explicit RETAIN statement or an implicit Sum Statement (variable + expression;).


Default DATA Step Re-initialization

To understand accumulation, you must understand the PDV lifecycle:

  1. Input Variables (read via SET, MERGE, MODIFY, or INPUT): Retain their values as new rows are read.
  2. 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, whereas Total = 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:

  1. Implicit Creation: Creates variable as a numeric variable if it does not already exist.
  2. Implicit Initial Value: Sets variable initial value to 0 before processing the first observation.
  3. Implicit RETAIN: Retains variable across all DATA step iterations.
  4. Missing Value Immunity: Adds the value of expression to variable, treating missing values in expression as 0 (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 / BehaviorExplicit Assignment (Total = Total + Amount; with RETAIN Total 0;)SAS Sum Statement (Total + Amount;)
SyntaxRequires RETAIN statement + Total = Total + Amount;Total + Amount; (No RETAIN, no =)
Default Initial ValueMissing (.) unless explicitly specified in RETAIN Total 0;Automatically initialized to 0
Handling Missing AmountEvaluates to missing (.), corrupting Total for all subsequent rows!Treats missing Amount as 0, preserving running total
SAS Log Behavior on MissingWrites diagnostic note: Missing values were generated...Silent execution; no log warnings
Recommended Use CaseWhen custom initial values (e.g., 100) or complex logic are neededStandard 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

  1. When Region changes to 'Asia', First.Region is 1. SAS sets RegionSales = 0.
  2. RegionSales + Sales; adds the current row's sales.
  3. Intermediate rows (First.Region = 0, Last.Region = 0) accumulate sales without outputting because if Last.Region; filters them out.
  4. On the final row of 'Asia', Last.Region is 1. The subsetting IF evaluates to true, and SAS outputs the summary record containing Region and the accumulated RegionSales subtotal.
Test Your Knowledge

What are the four implicit characteristics of a SAS Sum Statement (Count + 1; or Total + Sales;)?

A
B
C
D
Test Your Knowledge

Consider the following DATA step:

data work.summary;
   set work.sales;
   by Department;
   if First.Department then SalesTotal = 0;
   SalesTotal + Revenue;
   if Last.Department;
run;
What is the role of if Last.Department; in this program?

A
B
C
D
Test Your Knowledge

A programmer uses explicit assignment to calculate a running total:

data work.calc;
   set work.transactions;
   retain Total 0;
   Total = Total + Amount;
run;
If Amount is missing (.) on observation 3, what will be the value of Total for observation 3 and all subsequent observations?

A
B
C
D
Test Your Knowledge

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;)?

A
B
C
D