4.5 Processing Data Iteratively with DO Loops

Key Takeaways

  • DO loops exist to eliminate redundant code and perform repetitive calculations: twelve near-identical assignment statements collapse into one indexed loop that scales when columns are added.
  • An iterative DO loop executes a block of SAS statements repeatedly as an index variable increments from a specified start value to a stop value by a defined increment.
  • Upon exiting an iterative DO loop, the index variable retains a value equal to the stop value PLUS the increment value (e.g., DO i=1 TO 10; leaves i=11 after loop exit).
  • A DO WHILE (condition) loop evaluates its expression BEFORE executing the loop body (pre-test); if the condition evaluates to false on entry, the loop body executes zero times.
  • A DO UNTIL (condition) loop evaluates its expression AFTER executing the loop body (post-test); the loop body ALWAYS executes at least once regardless of initial condition state.
Last updated: August 2026

4.5 Processing Data Iteratively with DO Loops

Quick Answer: DO loops allow SAS to execute a block of code repetitively. An iterative DO loop uses an index variable that increments from a start value to a stop value. A DO WHILE loop repeats while a condition remains true (evaluating before each execution). A DO UNTIL loop repeats until a condition becomes true (evaluating after each execution, guaranteeing at least one execution).


Iterative DO Loops Mechanics

An iterative DO loop executes statements a specified number of times using an index variable.

Syntax

DO index-variable = start TO stop <BY increment>;
   /* SAS statements to execute repeatedly */
END;
  • index-variable: A numeric variable created in the PDV that tracks iteration count.
  • start: Initial value of the index variable.
  • stop: Target boundary value.
  • BY increment: Optional increment step size (default is 1).
data work.table_of_squares;
   do i = 1 to 5;
      Square = i ** 2;
   end;
run;

CRITICAL EXAM CONCEPT: Index Variable Value Upon Exit

One of the most frequently tested questions on the SAS Base Specialist exam asks for the value of the index variable after an iterative DO loop finishes.

Let me trace do i = 1 to 5; step-by-step:

  1. Iteration 1: i is set to 1. 1 <= 5 is true. Square = 1. END increments i to 2.
  2. Iteration 2: i is 2. 2 <= 5 is true. Square = 4. END increments i to 3.
  3. Iteration 3: i is 3. 3 <= 5 is true. Square = 9. END increments i to 4.
  4. Iteration 4: i is 4. 4 <= 5 is true. Square = 16. END increments i to 5.
  5. Iteration 5: i is 5. 5 <= 5 is true. Square = 25. END increments i to 6.
  6. Loop Evaluation: SAS checks i <= 5 (6 <= 5). Condition is FALSE. Loop terminates!

Golden Rule: When an iterative DO loop terminates normally, the index variable's stored value in the PDV is equal to stop + increment (e.g., 5 + 1 = 6).


Eliminating Redundant Code and Repetitive Calculations

The content guide states the practical purpose of iterative loops explicitly: use DO loops to eliminate redundant code and to perform repetitive calculations. Any time the same statement is written more than twice with only an index changing, a DO loop is the intended replacement.

/* REDUNDANT: twelve near-identical statements, twelve chances to typo */
data work.monthly_adjusted;
   set work.monthly_raw;
   Mon1  = Mon1  * 1.03;
   Mon2  = Mon2  * 1.03;
   Mon3  = Mon3  * 1.03;
   /* ... nine more lines ... */
   Mon12 = Mon12 * 1.03;
run;

/* CONCISE: one loop, one rate to change, no chance of a skipped month */
data work.monthly_adjusted;
   set work.monthly_raw;
   array mon{12} Mon1-Mon12;
   do i = 1 to 12;
      mon{i} = mon{i} * 1.03;
   end;
   drop i;
run;

The second use is the repetitive calculation: generating a series of values that do not exist in the input at all.

/* Ten-year projection generated from a single input row */
data work.amortisation;
   Principal = 250000;
   Rate      = 0.055;

   do Year = 1 to 10;
      Interest  = Principal * Rate;
      Principal = Principal - 12000 + Interest;
      output;                       /* one row per projected year */
   end;
   format Principal Interest dollar12.2;
run;
BenefitWhy it matters on the exam
Fewer lines to mistypeSyntax errors on a performance-based exam cost time you cannot recover
One place to change a constantA rate written twelve times will eventually disagree with itself
Scales with the datado i = 1 to dim(mon); adapts automatically when a column is added
Generates rows absent from the inputThe only way to build projections, schedules, and simulations in a DATA step

Explicit OUTPUT Statements Inside DO Loops

By default, a DATA step writes an observation to the output dataset only once per DATA step iteration (when reaching the RUN; statement). Placing an explicit OUTPUT; statement inside a DO loop alters this behavior completely.

Generating Multiple Observations per Data Step Iteration

data work.investment_growth;
   Capital = 10000;
   Rate = 0.05;
   
   do Year = 1 to 10;
      Capital = Capital * (1 + Rate);
      output; /* Writes a row FOR EVERY YEAR iteration of the loop! */
   end;
run;

In work.investment_growth, the explicit OUTPUT; statement inside the loop outputs 10 observations (one for each year). Furthermore, placing an explicit OUTPUT statement anywhere in a DATA step suppresses the automatic output at the bottom of the DATA step.


Conditional Loops: DO WHILE vs. DO UNTIL

When the number of required iterations is unknown in advance (e.g., calculating how many years until an investment doubles), use conditional DO loops.

DO WHILE Loop (Pre-Test Loop)

Evaluates the condition BEFORE executing the loop body.

DO WHILE (expression);
   /* statements */
END;
  • Executes as long as expression is TRUE.
  • If expression is FALSE on entry, the loop body executes 0 times.
data work.while_example;
   Capital = 100000; /* Capital is ALREADY >= 50000 */
   Years = 0;
   
   /* Evaluates (Capital < 50000) BEFORE entry -> FALSE! */
   do while (Capital < 50000);
      Years + 1;
      Capital = Capital * 1.05;
   end;
run;
/* Result: Years = 0, Capital = 100000 (Loop executed 0 times) */

DO UNTIL Loop (Post-Test Loop)

Evaluates the condition AFTER executing the loop body.

DO UNTIL (expression);
   /* statements */
END;
  • Executes as long as expression is FALSE, terminating when it becomes TRUE.
  • Because the test occurs at END, the loop body ALWAYS executes at least ONCE.
data work.until_example;
   Capital = 100000; /* Capital is ALREADY >= 50000 */
   Years = 0;
   
   /* Executes body FIRST, then evaluates (Capital >= 50000) -> TRUE! Terminates loop. */
   do until (Capital >= 50000);
      Years + 1;
      Capital = Capital * 1.05;
   end;
run;
/* Result: Years = 1, Capital = 105000 (Loop executed 1 time!) */

Nested DO Loops

A DO loop may contain another DO loop. Each nested loop needs its own index variable and its own END; statement, and the inner loop runs to completion on every single iteration of the outer loop. Total iterations equal the product of the two ranges.

/* Build a 3-region x 4-quarter forecasting grid = 12 observations */
data work.forecast_grid;
   set work.base_rates;              /* one input row: BaseAmount */

   do RegionNum = 1 to 3;            /* OUTER loop: 3 iterations  */
      do Quarter = 1 to 4;           /* INNER loop: 4 per region  */
         Projected = BaseAmount * (1 + 0.02 * Quarter) * RegionNum;
         output;                     /* 3 x 4 = 12 rows written   */
      end;                           /* closes the INNER loop     */
   end;                              /* closes the OUTER loop     */
run;

Rules and Traps for Nested Loops

  1. One END; per DO — an unmatched END makes SAS swallow the rest of the DATA step and usually produces a confusing ERROR: There is an extra END statement or an infinite construct.
  2. Distinct index variables — reusing i for both loops causes the inner loop to overwrite the outer counter, so the outer loop never advances correctly.
  3. Where OUTPUT; sits determines the row count — inside the inner loop you get 12 rows; between end; and end; you get 3 rows; after both end; statements you get 1 row.
  4. Index values after exit — each index still ends at stop + increment (RegionNum = 4, Quarter = 5) unless you drop them.

Comparison: DO Loop Variants

FeatureIterative DODO WHILEDO UNTIL
Test TimingBefore each iterationPre-test (Before loop body)Post-test (After loop body)
Termination ConditionIndex exceeds stop valueExpression becomes FALSEExpression becomes TRUE
Minimum Iterations0 (if start > stop)0 iterations1 iteration (Guaranteed)
Index VariableManaged automaticallyManaged manually inside loopManaged manually inside loop
Common Use CaseFixed counts, arraysCondition monitoring (0+ runs)Condition monitoring (1+ runs)

Combining Iterative and Conditional Clauses

You can combine iterative index processing with WHILE or UNTIL clauses to set safety limits and prevent infinite loops:

data work.safe_projection;
   Capital = 10000;
   
   /* Runs for a maximum of 30 years OR UNTIL Capital reaches 50,000 */
   do Year = 1 to 30 until (Capital >= 50000);
      Capital = Capital * 1.07;
   end;
run;
Test Your Knowledge

Consider the following SAS DATA step:

data work.test;
   do i = 1 to 5;
      Square = i * i;
   end;
run;
How many observations are written to work.test, and what is the value of i stored in the output dataset?

A
B
C
D
Test Your Knowledge

A financial analyst wants to calculate compound interest until capital reaches $100,000, ensuring that the calculation loop executes AT LEAST ONCE even if initial capital is already $100,000 or more. Which DO loop structure guarantees at least one execution?

A
B
C
D
Test Your Knowledge

What is the primary effect of placing an explicit OUTPUT; statement inside an iterative DO loop in a SAS DATA step?

A
B
C
D
Test Your Knowledge

Consider the following DO WHILE loop code segment:

data work.growth;
   Invest = 1000;
   Year = 0;
   do while (Invest < 1000);
      Year + 1;
      Invest = Invest * 1.05;
   end;
run;
What are the final values of Year and Invest stored in work.growth?

A
B
C
D