Hi,
I'm trying do have a do loop within a macro but can't seem to get it to work
the data I have...
data have;
input id $ severity_1 $ severity_2 $ severity_3 $;
datalines;
001 WARNING N/A N/A
002 N/A N/A N/A
003 N/A WARNING N/A
run;
what I want to do...
data want;
set have;
if severity_1 = "WARNING" or severity_2 = "WARNING" or severity_3 = "WARNING" then data_invalid = "Y"; else data_invalid = "N";
run;
the reason I want a do loop is because there will be 100 severity columns
what I have so far (that does not seem to work)...
%macro data_invalid();
data want2;
set have;
%let i=1;
%do %while (i < 3);
%if severity_&i = "WARNING" %then data_invalid = "Y" %else data_invalid = "N"
%end;
run;
%mend;
%data_invalid();
proc freq data = want2;
table data_invalid /missing;
run;
the error I get is "variable data_invalid not found"
Help?
This is NOT a macro problem. Just use an ARRAY in the data step.
data want;
set have;
array sev severity_1 - severity_3 ;
data_invalid = "N";
do index=1 to dim(sev) while ( data_invalid = "N");
if sev[index] = "WARNING" then data_invalid = "Y";
end;
drop index;
run;
You don't need a macro but use a whichc() function on an array:
data invalid;
set have;
array sx {} $ severity_: ; /* or severity_1 - severity_3 */
if whichc(sx(*)) = "WARNING" then data_invalid = "y"; else data_invalid = "N";
run;
@Shmuel wrote:
You don't need a macro but use a whichc() function on an array:
data invalid; set have; array sx {} severiity_: ; /* or severity_1 - severity_3 */ if whichc(sx(*)) = "WARNING" then data_invalid = "y"; else data_invalid = "N"; run;
Correction on syntax of the WHICHC() function. Also another advantage of using WHICHC() for this is you don't need to define the array. Just use the variable list in the function call.
data invalid;
set have;
if whichc("WARNING", of severity_:) then data_invalid = "Y";
else data_invalid = "N";
run;
Thank you @Tom
This is NOT a macro problem. Just use an ARRAY in the data step.
data want;
set have;
array sev severity_1 - severity_3 ;
data_invalid = "N";
do index=1 to dim(sev) while ( data_invalid = "N");
if sev[index] = "WARNING" then data_invalid = "Y";
end;
drop index;
run;
thanks once again @Tom
@Shmuel 's answer.
Given that macro are not needed, there are several reasons your macro doesn't work :
- You use macro %if...%then...%else but should use regular if...then...else as the macro versions
only make text comparisons. So the condition severity_&i = "WARNING" will compare two strings
(for &i.=2, for instance), severity_2 (wo quotes) and "WARNING" (with quotes) and will never be true
- You repeat the test for each value of &i. so that only the last test will influence the final value of invalid_data.
You should generate a series of tests separated by "or".
- You forgot a semi-colon after %then data_invalid = "Y"
Also, you can use a simple %do loop :
%do i=1 %to 3;
...
%end;
Hi @twenty7,
Alternatively you can use the IN operator with an array:
data want;
set have;
array s[*] sev:;
data_invalid='WARNING' in s;
run;
Note that this creates a numeric, 0-1 coded variable data_invalid, which is more convenient than a character variable in most applications. Apply a format if you need to see "N" and "Y" in your output.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.
Ready to level-up your skills? Choose your own adventure.