Attempts at coding economy can lead you astray.
In the following why does the loop continue past 'g' ?
data _null_; length message $200; do s='a','b','d','g','x','y','z' until (not missing(message)); message = ifc (s='g','Hey, s reached ' || s,''); msg_is_not_missing = not missing(message); put s= msg_is_not_missing= message=; end; run;
Which logs
s=a msg_is_not_missing=0 message= s=b msg_is_not_missing=0 message= s=d msg_is_not_missing=0 message= s=g msg_is_not_missing=1 message=Hey, s reached g /* why does loop keep going */ s=x msg_is_not_missing=0 message= s=y msg_is_not_missing=0 message= s=z msg_is_not_missing=0 message=
Turns out the UNTIL applies only to the specification it is associated with, and DO can have multiple specifications separated by commas.
Reformatting the code so each specification is on its own line makes the reason/rule a little more clear:
do s = 'a'
, 'b'
, 'd'
, 'g' /* no until here */
, 'x'
, 'y'
, 'z' until (not missing(message))
;
To escape the loop according to initial expectations you would have to code inside the DO
if not missing (message) then leave;
I found this in the documentation:
In this example, the DO loop is executed when I=1 and I=2. The WHILE condition is evaluated when I=3, and the DO loop is executed if the WHILE condition is true.
do i=1,2,3 while (condition);
Very interesting.
In the DO statement, commas prevail over while and until. I initially found this a bit counterintuitive, but it has the great advantage of allowing distinct WHILE/UNTIL clauses for each of the comma-separated ranges:
data _null_;
do i=1 to 3 until (i>=2), 101 to 103 while (i<=102), 1001 to 1003 while (i<1000),10001 to 10002;
put i=;
end;
run;
According to SAS documentation for DO Statement: Iterative, "A WHILE or UNTIL specification affects only the last item in the clause in which it is located", in your case it is s='z'.
Hope this helps.
The other way you could re-code is to switch from UNTIL() to WHILE().
do s = 'a'
, 'b' while (missing(message))
, 'd' while (missing(message))
, 'g' while (missing(message))
, 'x' while (missing(message))
, 'y' while (missing(message))
, 'z' while (missing(message))
;
Leaving the WHILE condition off the first makes work like the UNTIL() in an indexed loop:
do i = 1 to 5 until (not missing(message));
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.