***total number for each siteid
A 100
B 200
C 300
;
data have;
input trtn siteid $ f1 ;
cards;
1 A 10
2 A 15
3 A 25
1 B 10
2 B 15
3 B 25
1 C 10
2 C 15
3 C 25
;
run;
%let n1=100;
%let n2=200;
%let n3=300;
data pct;
length npct $200;
set have;
if trtn=1 then npct=strip(put(f1,best.))||" ("||strip(put(f1/&n1*100,5.1))||")";
if trtn=2 then npct=strip(put(f1,best.))||" ("||strip(put(f1/&n2*100,5.1))||")";
if trtn=3 then npct=strip(put(f1,best.))||" ("||strip(put(f1/&n3*100,5.1))||")";
run;
option symbolgen mprint mlogic;
%MACRO PCT;
DATA pct;
LENGTH NPCT $200;
SET have;
%*why &i=trtn is false, how to modify the code??;
%DO i=1 %TO 3;
%if &i=trtn %then %do;
n=&&n&i;
if f1>. and n>. then NPCT=strip(put(F1,best.))||" ("||strip(put(F1/n*100,5.1))||")";
%end;
%END;
RUN;
%MEND;
%PCT;
the result in the data step is what I want, but the macro %pct cannot work, why? how?
It doesn't work because the value of &I can only be the digit strings 1 , 2 or 3 and none of those will ever equal the string trtn.
If you want to use a %DO loop to recreate the repetitive code in your first step then there is no need for and %IF statements.
Just replace the digit 1 with &i in the first example. Make sure to add an extra & so that you can get the value of macro variable N1 instead of the value of macro variable N.
data pct;
length npct $200;
set have;
%do i=1 %to 3 ;
if trtn=&i then npct=strip(put(f1,best.))||" ("||strip(put(f1/&&n&i*100,5.1))||")";
%end;
run;
Or just eliminate the need for any looping by using the SYMGETN() function instead.
data pct;
length npct $200;
set have;
npct=strip(put(f1,best.))||" ("||strip(put(f1/symgetn(cats('N',trtn))*100,5.1))||")";
run;
Sorry for my mistake,
updated as below:
***total number for each trtn
trtn total
1 100
2 200
3 300
;
Because you are comparing the value of macro variable i with the string trtn - which is always false, because of your definition of i. Why do you use macro-statements at all?
Sounds like you want to compare the value of the data step variable TRTN to a literal value that happens to come from resolving &i.
When you want to evaluate the value of a data step variable, you use a data step IF statement, not a macro %IF statement.
Thus if you change your code to:
%MACRO PCT;
%local i;
DATA pct;
LENGTH NPCT $200;
SET have;
%DO i=1 %TO 3;
if &i=trtn then do;
n=&&n&i;
if f1>. and n>. then NPCT=strip(put(F1,best.))||" ("||strip(put(F1/n*100,5.1))||")";
end;
%END;
RUN;
%MEND;
%PCT;
The code works. Note that the macro is simply generating SAS code. The above macro will generate:
DATA pct;
LENGTH NPCT $200;
SET have;
if 1=trtn then do;
n=100;
if f1>. and n>. then NPCT=strip(put(F1,best.))||" ("||strip(put(F1/n*100,5.1))||")";
end;
if 2=trtn then do;
n=200;
if f1>. and n>. then NPCT=strip(put(F1,best.))||" ("||strip(put(F1/n*100,5.1))||")";
end;
if 3=trtn then do;
n=300;
if f1>. and n>. then NPCT=strip(put(F1,best.))||" ("||strip(put(F1/n*100,5.1))||")";
end;
RUN;
Looking at that step showing the generated code, there are likely better ways in SAS to write this sort of lookup. But the code is valid syntax.
You do not need a macro at all, as proper lookup technique is done with data step means only:
data have;
input trtn siteid $ f1;
cards;
1 A 10
2 A 15
3 A 25
1 B 10
2 B 15
3 B 25
1 C 10
2 C 15
3 C 25
;
data lookup;
input trtn n;
datalines;
1 100
2 200
3 300
;
data pct;
length npct $200;
set have;
if _n_ = 1
then do;
declare hash lookup (dataset:"lookup");
lookup.definekey('trtn');
lookup.definedata('n');
lookup.definedone();
n = 0; * prevents "uninitialized" NOTE;
end;
if lookup.find() = 0 then npct=strip(put(f1,best.))||" ("||strip(put(f1/n*100,5.1))||")";
drop n;
run;
In place of the hash, you could also use a join or an informat created from the dataset, but the hash is the way to go for issues like this.
Please post the expected result you want out of your example data.
It doesn't work because the value of &I can only be the digit strings 1 , 2 or 3 and none of those will ever equal the string trtn.
If you want to use a %DO loop to recreate the repetitive code in your first step then there is no need for and %IF statements.
Just replace the digit 1 with &i in the first example. Make sure to add an extra & so that you can get the value of macro variable N1 instead of the value of macro variable N.
data pct;
length npct $200;
set have;
%do i=1 %to 3 ;
if trtn=&i then npct=strip(put(f1,best.))||" ("||strip(put(f1/&&n&i*100,5.1))||")";
%end;
run;
Or just eliminate the need for any looping by using the SYMGETN() function instead.
data pct;
length npct $200;
set have;
npct=strip(put(f1,best.))||" ("||strip(put(f1/symgetn(cats('N',trtn))*100,5.1))||")";
run;
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.