BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
alepage
Barite | Level 11

the do while is not working.

What's wrong ?

 

data paths;
     length path $200;
     input path $;
     datalines;
/dwh_actuariat/sasprocess/prodmens/HYFIprep/output
/dwh_actuariat/sasprocess/prodmens/HYFIp/output
;
run;
%macro process;
proc sql noprint;
     select path into :path_list separated by ' '
     from paths;
quit;

%put &=path_list;


%let i = 1;
%do %while (%scan(&path_list, &i. , ' ') ne '');
     %let current_path = %scan(&path_list, &i. , ' ');
     %put &=current_path;
     %let i = %eval(&i. + 1);
%end;


%mend process;
%process;
1 ACCEPTED SOLUTION

Accepted Solutions
Ksharp
Super User
data paths;
     length path $200;
     input path $;
     datalines;
/dwh_actuariat/sasprocess/prodmens/HYFIprep/output
/dwh_actuariat/sasprocess/prodmens/HYFIp/output
;
run;
%macro process;
proc sql noprint;
     select path into :path_list separated by ' '
     from paths;
quit;

%put &=path_list;


%let i = 1;
%do %while (%qscan(&path_list, &i. ,%str( )) ne );
     %let current_path = %scan(&path_list, &i. , %str( ));
     %put &=current_path;
     %let i = %eval(&i. + 1);
%end;


%mend process;
%process;

View solution in original post

17 REPLIES 17
Ksharp
Super User
data paths;
     length path $200;
     input path $;
     datalines;
/dwh_actuariat/sasprocess/prodmens/HYFIprep/output
/dwh_actuariat/sasprocess/prodmens/HYFIp/output
;
run;
%macro process;
proc sql noprint;
     select path into :path_list separated by ' '
     from paths;
quit;

%put &=path_list;


%let i = 1;
%do %while (%qscan(&path_list, &i. ,%str( )) ne );
     %let current_path = %scan(&path_list, &i. , %str( ));
     %put &=current_path;
     %let i = %eval(&i. + 1);
%end;


%mend process;
%process;
Kurt_Bremser
Super User

In its current form, the macro does nothing but write values to the log, which can easily be achieved in a single DATA step without any macro language.

What is your real task?

Ksharp
Super User
Kurt,
I just copy the code from OP and fixed it.
I have no idea about what is OP's intention.
alepage
Barite | Level 11
I will replace the %put by another macro function.
alepage
Barite | Level 11
Why did you replace the %scan by %pscan and the '' by %str() and ne )

Please explain.
Your script work perfectly
Tom
Super User Tom
Super User

@alepage wrote:
Why did you replace the %scan by %pscan and the '' by %str() and ne )

Please explain.
Your script work perfectly

%QSCAN() adds macro quoting to the path so that %EVAL() does not see the / as division symbols.

 

You do not need to enclose strings in quotes for the macro processor.  The reason you need the quotes in SAS code is so SAS knows what to treat as strings and what to treat as variable names or keywords.  But to the macro processor everything is a string. So the quotes become part of the string. 

Ksharp
Super User

1)Actually, @Tom has already answered your question.
The secret hided in operator "NE".
When sas meet "NE" ,would put %eval() around "/dwh_actuariat/sasprocess/prodmens/HYFIp/output"
and since "/" is a divided operator in sas ,sas would take it as a divided operator, and lead to this error.
Here I use %QSCAN() is to mask "/" operator to avoid this error as Tom show you detailly .

 

2)A white blank is  a special character in MACRO language, so I use %str( ) to mask it to let MACRO know it as I use %qscan() to mask "/“ divided operator.

 

3)As @Tom  pointed out MACRO take everything as a STRING , you don't need to put quote around it just leave it as a blank . Otherwise, MACRO would take it as "a blank", not a NULL character(empty).

Tom
Super User Tom
Super User

Why did you tell SQL to use space as the delimiter and tell %SCAN() to also include single quote as a delimiter?   And why did you compare the value to something that does contain single quote characters? That will never match as the result of the %SCAN() function could never contain any single quotes since they are being used as delimiters.

 

Note since you want to use %SCAN() to split the macro variable it will work better to use some character that cannot appear in a path as the delimiter, such as a | character.

 

Also SAS will not like those / characters in the strings generated by the %SCAN() call.  

PATH_LIST=/dwh_actuariat/sasprocess/prodmens/HYFIprep/output /dwh_actuariat/sasprocess/prodmens/HYFIp/output
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
       %scan(&path_list, &i. ,  ) ne
ERROR: The condition in the %DO %WHILE loop, %scan(&path_list, &i. ,  ) ne, yielded an invalid or missing value, .  The macro
       will stop executing.
ERROR: The macro PROCESS will stop executing.

If you want to get your complex looping code to work make sure to use the right delimiter and compare to and actual empty value and use macro quoting to protect the value of the path from confusing the %EVAL() used by the %WHILE().

%do %while (%qscan(&path_list, &i. , %str( )) ne );

But why would you use such a complex loop when you can just use a NORMAL iterative do loop?

%macro process;
%local path_list i n current_path;
proc sql noprint;
  select path into :path_list separated by '|'
  from paths;
quit;
%let n=&sqlobs;

%do i=1 %to &n;
  %let current_path = %scan(&path_list, &i. ,|);
  %put &=i &=current_path;
%end;
%mend process;

Results

I=1 CURRENT_PATH=/dwh_actuariat/sasprocess/prodmens/HYFIprep/output
I=2 CURRENT_PATH=/dwh_actuariat/sasprocess/prodmens/HYFIp/output

And if you want to loop over a delimited list where you don't know the number of items in advance just count them.

%do i=1 %to %sysfunc(countw(&path_list,|));
  %let current_path = %scan(&path_list, &i. ,|);
  %put &=i &=current_path;
%end;
andreas_lds
Jade | Level 19

From my point of view the first error is moving data from a dataset into macro variables, which is not necessary in most cases.

yabwon
Amethyst | Level 16

How about using macroArray packge and create a macro variable array?

1)  Documentation

2) Article describing the package.

 

Example:

 

/* load package to your SAS session */
%loadPackage(macroArray)


/* data */
data paths;
     length path $200;
     input path $;
     datalines;
/dwh_actuariat/sasprocess/prodmens/HYFIprep/output
/dwh_actuariat/sasprocess/prodmens/HYFIp/output
;
run;


/* create m.v.a. Path */
%array(ds=paths,vars=path,macarray=Y)

/*
optionally preview:
%put %do_over(path);
*/

/* use macro variable array  */
%macro test(i);

%do i = 1 %to &i.;
  %put &=i. #%path(&i.)#; /* call %path() macro to get values one by one */
%end;

%mend;

%test(&pathN.) /* pathN macro variable keep size */

/* clean up */
%deleteMacArray(path,macarray=Y)

 

 

Log:

 

1
2
3    data paths;
4         length path $200;
5         input path $;
6         datalines;

NOTE: The data set WORK.PATHS has 2 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      user cpu time       0.00 seconds
      system cpu time     0.00 seconds
      memory              404.96k
      OS Memory           25908.00k
      Timestamp           08/21/2025 09:24:43 AM
      Step Count                        289  Switch Count  0


9    ;
10   run;
11
12
13   /* create */
14   %array(ds=paths,vars=path,macarray=Y)
NOTE:[ARRAY] 2 macrovariables created
15
16   /*
17   optionally preview:
18   %put %do_over(path);
19   */
20
21   /* use macro variable array  */
22   %macro test(i);
23
24   %do i = 1 %to &i.;
25     %put &=i. #%path(&i.)#;
26   %end;
27
28   %mend;
29
30   %test(&pathN.)
I=1 #/dwh_actuariat/sasprocess/prodmens/HYFIprep/output#
I=2 #/dwh_actuariat/sasprocess/prodmens/HYFIp/output#
31
32   /* clean up */
33   %deleteMacArray(path,macarray=Y)

 

 

 

Bart

 

P.S. How to install MacroArray package?

 

1) Create a directory of your convenience, for example:

  • C:\users\myuser\Desktop\Packages

2) In your SAS session, run the following line of code:

filename packages "C:\users\myuser\Desktop\Packages";

For Linux change the path accordingly

3) To install the SAS Packages Framework, execute the code (only one time):

/* enable a temporary version of the framework */
filename SPFinit url 
 "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";      
%include SPFinit; 

/* install the framework */
%installPackage(SPFinit)

filename SPFinit clear;

4) To install the package macroArray run the following code:

%installPackage(macroArray)

 

5) In order to use the SPF and packages in a SAS session, they must be enabled and loaded first. This is very straightforward, all we need to do is to assign the packages filename to the packages directory, then include the framework code, and load a package we need. To do so execute 3 lines of code:

filename packages "/path/to/my/packages";
%include packages(SPFinit.sas);
%loadPackage(macroArray)

 

See SAS packages tutorial for more details.

 

 

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



PaigeMiller
Diamond | Level 26

Agreeing with @Kurt_Bremser , there is no point in using macros for this task. So @alepage what is the real problem you are trying to solve?

--
Paige Miller
alepage
Barite | Level 11

Well I want to use the macro process to passed as parameter the two different paths.  Then I will replace the %put statement by another macro function that is loading all the txt files into that folder into a sas dataset.

Tom
Super User Tom
Super User

@alepage wrote:

Well I want to use the macro process to passed as parameter the two different paths.  Then I will replace the %put statement by another macro function that is loading all the txt files into that folder into a sas dataset.


So skip the macro and the macro variables and just use a data step to generate the calls to the macro.

 

So if your macro is named %MYMACRO() and takes the path as the first positional argument you could generate one call to the macro for each observation in the data PATHS with this data step:

data _null_;
  set paths;
  call execute(cats('%nrstr(%mymacro)(',path,')'));
run;

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!

Register Now

Creating Custom Steps in SAS Studio

Check out this tutorial series to learn how to build your own steps in SAS Studio.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 17 replies
  • 1078 views
  • 12 likes
  • 7 in conversation