That difference matters when your calculation means “change since the preceding row for this account.” Write that rule explicitly; the name lag alone does not establish it.
Calculate the expected rows before changing the code
This original fictional dataset is already ordered by account and day. For the exercise, each account's first change is missing, and later changes subtract the immediately preceding row within the same account:
| Account | Day | Value | Expected previous value | Expected change |
|---|---|---|---|---|
| A | 1 | 10 | Missing | Missing |
| A | 2 | 13 | 10 | 3 |
| B | 1 | 20 | Missing | Missing |
| B | 2 | 24 | 20 | 4 |
The first B row must not use A's 13. The second A row must use 10, even though the first A row does not receive a change.
SAS's official LAG reference, checked October 24, 2026, explains that each occurrence has its own queue and that execution advances that queue. It includes conditional execution and BY-group examples.
Find the call that skips a row
This proposed pattern is wrong for the fixture's rule:
if not first.account then previous = lag(value);
At A day 1, the call is skipped, so 10 never enters that queue. At A day 2, its first execution returns the queue's initial missing value and enqueues 13. At B day 1, the call is skipped again. At B day 2, the next execution returns 13 from A, not B's 20.
The condition controls more than the assignment: it controls which values enter the queue. A different occurrence of lag(value) elsewhere in the step has its own queue, so it cannot repair this call's missing history.
Advance on every row and apply the group boundary afterward
For this already ordered fixture, one proposed complete practice program is:
data have;
input account $ day value;
datalines;
A 1 10
A 2 13
B 1 20
B 2 24
;
run;
data want;
set have;
by account day;
previous = lag(value);
if first.account then call missing(previous);
change = value - previous;
run;
proc print data=want noobs;
var account day value previous change;
run;
The unconditional call enqueues each row's value. The first-row assignment then clears the returned value for the output's group boundary; it does not reset the underlying queue. Thus B day 1 suppresses A's 13 while still enqueuing B's 20. B day 2 can then return 20.
The expected changes are missing, 3, missing and 4. This is a reasoned practice fixture, not recorded output from a SAS session. Run it in your SAS environment and compare all four rows before adapting the step.
Ask for the queue trace and the ordering contract
Review this SAS DATA step without changing the source dataset.
SAS version and complete relevant step: [PASTE]
Input rows in actual processing order: [PASTE PERMITTED SAMPLE]
BY variables and whether sorting has been verified: [ENTER]
Meaning of previous: [PREVIOUS ROW / PREVIOUS QUALIFYING ROW / OTHER]
Group boundary and missing-value rules: [ENTER]
Expected previous/change columns: [PASTE]
Trace every execution of each LAG occurrence and the value it returns.
Explain skipped calls, separate queues and first-group observations.
Propose syntax matching my exact rule and checks for the first two
rows of every group. Do not silently sort, drop rows, invent a unique
tie-breaker, overwrite data or claim a successful SAS run.
For actual data, establish tie handling when an account has two observations on the same day. Also decide whether “previous” means the preceding observed row or the previous calendar day; this fixture uses the preceding row and does not fill missing days.
OpenAI's prompting guidance supports providing context and boundaries. In this request, processing order and the meaning of previous are the facts that determine the answer.
The time-series evaluation guide addresses what was knowable at a forecast origin. This SAS task instead establishes what the DATA step's queue actually contains. Keep the accepted step, processing-order rule and expected group-boundary rows together so a later conditional edit cannot quietly change the calculation.