SAS macro if then else always ELSE - sas

During making some heatmap I face with some problem. All my cells is painting with yellow! MLOGIC show that all the statements TRUE with yellow colour but the values in cells is a different? there is all red and white. Could you tell me my mistake& Thank you! The code and log below:
%macro main;
ods html body='temp.html';
proc report data=step3 nowd;
column kri_id range_mid_1 range_mid_2
%do i=1 %to 9;
a2017_M0&i. %end;
;
define kri_id / display;
define range_mid_1 / display;
define range_mid_2 / display;
%do i=1 %to 9;
define a2017_M0&i. / display;
%end;
%do p=1 %to 9;
compute a2017_M0&p.;
%if a2017_M0&p. > range_mid_2
%then call define(_col_, "style", "STYLE=[background=red]");
%else %if range_mid_1 < a2017_M0&p. < range_mid_2
%then call define(_col_, "style", "STYLE=[background=yellow]");
;endcomp;
%end;
;run;
ods html close;
ods html body='temp.html';
%mend; %main;
Log file is bellow
SYMBOLGEN: Macro variable P resolves to 1
MLOGIC(MAIN): %IF condition a2017_M0&p. > range_mid_2 is FALSE
SYMBOLGEN: Macro variable P resolves to 1
MLOGIC(MAIN): %IF condition range_mid_1 < a2017_M0&p. < range_mid_2 is TRUE
MPRINT(MAIN): call define(_col_, "style", "STYLE=[background=yellow]") ;
MPRINT(MAIN): endcomp;
MLOGIC(MAIN): %DO loop index variable P is now 2; loop will iterate again.
SYMBOLGEN: Macro variable P resolves to 2
MPRINT(MAIN): compute a2017_M02;
SYMBOLGEN: Macro variable P resolves to 2
MLOGIC(MAIN): %IF condition a2017_M0&p. > range_mid_2 is FALSE
SYMBOLGEN: Macro variable P resolves to 2
MLOGIC(MAIN): %IF condition range_mid_1 < a2017_M0&p. < range_mid_2 is TRUE
MPRINT(MAIN): call define(_col_, "style", "STYLE=[background=yellow]") ;
MPRINT(MAIN): endcomp;
MLOGIC(MAIN): %DO loop index variable P is now 3; loop will iterate again.
SYMBOLGEN: Macro variable P resolves to 3
MPRINT(MAIN): compute a2017_M03;
SYMBOLGEN: Macro variable P resolves to 3
MLOGIC(MAIN): %IF condition a2017_M0&p. > range_mid_2 is FALSE
SYMBOLGEN: Macro variable P resolves to 3
And ETC

You are using macro logic where you want actual SAS code logic.
The reason you are always getting the %ELSE clause is because the letter a is less than the letter r so this test is always false.
%if a2017_M0&p. > range_mid_2
To the macro processor a2017_M01 and range_mid_2 are just text strings. The macro processor knows nothing of your data set variables.

Thank you! With your help I found the answer here. I had to use IF THE ELSE without %. Than it compares the variables

Related

Why is the %IF statement not executing?

%macro SASIsAwful();
%let LastEnt = 12;
%let i = 1;
%do i = 1 %to &LastEnt.;
proc sql noprint;
select Diff into :CheckDiff from Trial01 where RowNum = &i.;
select ACTV_DTM into :CheckDate from Trial01 where RowNum = &i.;
create table Eval001 as select * from Trial01 where RowNum = &i.;
quit;
%if &CheckDiff. = 'N' %then %do; %put &CheckDiff.; %end;
%end;
%mend SASIsAwful;
I cannot for the life of me figure out why the %if statement did not work. Proc SQL worked fine, and I manually confirmed that it saved the value N into &CheckDiff. twelve times. Yet, for some reason, the %if statement never executed, and there was no error message. What went wrong here? Thank you.
The correct macro statement should be
%IF &CHECKDIFF = N %then ... ;
If you examine an unconditional %put, you will most likely see a log lines such as
%put INFO: &=CHECKDIFF;
--- log ---
INFO: CHECKDIFF=N;
INFO: CHECKDIFF=Y;
Richard is right.
Macrovars are always strings.
CheckDiff is just the 1-char-string N, which is different from the 3-char-string "N".
You could also write
%IF "&CHECKDIFF" = "N" %then ...
but not
%IF '&CHECKDIFF' = 'N' %then ...
because Macrovars are only replaced within double quotes, not single quotes.

How to use SAS macro with %DO and %IF

When I ran a macro, the PassengerID_Class had a null value.
I think there is a problem with the sentence below.
%if PassengerID >= &&P&i and PassengerID < &&P&k %then PassengerID_Class = &i. ;
PassengerID is a column containing values from 1 to 891.
P1,P2,...,Pi are the quantiles.
Below is my code.
%macro do_loop;
DATA _NULL_;
SET PERCENTILES100_Transpose;
call symput("P"||left(_n_),Column1);
RUN;
Data Groups100;
Set sample;
%do i=2 %to 99;
%Let k = %eval(&i.+1);
%if PassengerID >= &&P&i and PassengerID < &&P&k %then PassengerID_Class = &i. ;
%end;
%mend;
%do_loop;
You cannot test the value of dataset variable with a macro expression. Just use the macro to generate a normal IF statement, the same as you are using the macro to generate the DATA and other SAS statements.
if &&P&i <= PassengerID < &&P&k then PassengerID_Class = &i. ;
But why use macro code at all? Just read the cutoff values into a temporary array.
data Groups100;
set sample;
array p[100] _temporary_;
if _n_=1 then do index=1 by 1 until(eof);
set PERCENTILES100_Transpose(keep=column1) end=eof;
p[index]=column1;
end;
PassengerID_Class=0;
do index=2 to 99 until(PassengerID_Class>0);
if p[index] <= PassengerID < p[index+1] then PassengerID_Class = index ;
end;
drop index column1 ;
run;
Note that using the data directly will also avoid loss of precision caused by converting the numbers into text strings to store macro variables.

SAS %while loop condition not evaluating correctly

I'm running a macro loop to recursively strip out stock returns greater than the 99.5 percentile to calculate a volatility model. I'm trying to set the loop to run until there are no observations with a z-score (assuming standard normal for the percentile) greater than 2.58. For some reason though, the loop will not evaluate despite the condition being true. Here's the code that I'm using:
%macro delete_jump;
%let z_max=10.0;
%let i=0;
%let crit=%sysfunc(quantile(%str(NORMAL),0.995,0,1));
%put The critical value is &crit.;
%do %while((&z_max. > &crit.) and (&i. < 30));
%put max=&z_max.;
proc expand data=crsp_data out=crsp_data(drop=time);
convert ret_nojmp=ret_vol / transformout=(movstd &hist_pd. trimleft &hist_pd.);
convert ret_nojmp=ret_ma / transformout=(movave &hist_pd. trimleft &hist_pd.);
by ticker;
run;
data crsp_data(drop=ret_vol ret_ma);
set crsp_data(drop=zscore);
zscore=(ret_nojmp-ret_ma) / ret_vol;
if quantile("NORMAL",0.01,0,1) < zscore < quantile("NORMAL",0.99,0,1) then ret_nojmp=ret;
else ret_nojmp = .;
run;
proc sql;
select max(abs(zscore)) into :z_max
from crsp_data;
quit;
%let i=%eval(&i.+1);
%end;
%mend delete_jump;
I set z=10 to initialize the loop and i is just a counter so I can escape after a certain amount of time. When it gets to that point though, the log file says the following:
MLOGIC(DELETE_JUMP): Beginning execution.
MLOGIC(DELETE_JUMP): %LET (variable name is Z_MAX)
MLOGIC(DELETE_JUMP): %LET (variable name is I)
MLOGIC(DELETE_JUMP): %LET (variable name is CRIT)
MLOGIC(DELETE_JUMP): %PUT The critical value is &crit.
SYMBOLGEN: Macro variable CRIT resolves to 2.57582930354889
The critical value is 2.57582930354889
SYMBOLGEN: Macro variable Z_MAX resolves to 10.0
SYMBOLGEN: Macro variable CRIT resolves to 2.57582930354889
SYMBOLGEN: Macro variable I resolves to 0
MLOGIC(DELETE_JUMP): %DO %WHILE((&z_max. > &crit.) and (&i. < 30)) loop
beginning; condition is FALSE. Loop will not be executed.
MLOGIC(DELETE_JUMP): Ending execution.
I've tried splitting the conditions and hardcoding the value of CRIT, but it never executes the loop. Any thoughts are appreciated.
The problem seems to be that %do while uses %eval internally, which only works properly for integer comparisons, but you are comparing two decimals. Replace as follows and it should work as expected:
%do %while(%sysevalf(&z_max. > &crit.) and (&i. < 30));

Controlling program flow - sas

Below is the code to execute a set of data-steps based on the value of the increment variable "i". Since I have assigned the value of i to 1 (numeric and not character value). Ideally the first data-step block need to execute, but in the below case the second data-step block is executing.
%put &i. ; prints 1 in to the log window.
%macro DSN;
%let i = 1 ;
data new_DSN;
run;
%if i = 1 %then %do;
data Dummy ;
run;
data DUMMY_ ;
set DUMMY new_DSN ;
run;
%end;
%else %if i ^= 1 %then %do ;
data DUMMY_ ;
set DUMMY_ new_DSN ;
run;
%end;
%mend DSN;
%DSN;
Your IF statement is not calling &I macro variable, but simply comparing string I to 1. This also explains why your second loop running because technically speaking string "I" is not equal to "1". You just need to put ampersand in front of I in both %IF statements. I also put two %PUT statements to easier see where code is running. See below:
%macro DSN;
%let i = 1 ;
data new_DSN;
run;
%if &i = 1 %then %do;
%PUT First Loop Run;
data Dummy ;
run;
data DUMMY_ ;
set DUMMY new_DSN ;
run;
%end;
%else %if &i ^= 1 %then %do ;
%PUT Second Loop Run;
data DUMMY_ ;
set DUMMY_ new_DSN ;
run;
%end;
%mend DSN;
%DSN;

Getting error while running SAS code

I'm getting an error while running the below code. &CNT is 50 and &vars has column names in it.
Each column as some values from 1 to 100. I want to select each column and check the below criteria (%if statement), creating a new variable and assigning the values to it (like free, partially free and not free).
option mlogic mprint;
%macro analysis();
DATA Q2;
SET Q1;
%do i=1 %to &CNT.;
%let segs =%scan(&VARS.,&i.," ");
%IF &SEGS.<=2.5 %THEN &SEGS._R="FREE";
%ELSE %IF (&SEGS.>2.5 AND &SEGS.<5.5) %THEN &SEGS._R="PARTLY FREE";
%ELSE %IF &SEGS.>=5.5 %THEN &SEGS._R="NOT FREE";
/*%PUT &segs.;*/
%end;
RUN;
%MEND;
%analysis();
This is the output I'm getting:
SAS LOG ERROR:
MPRINT(ANALYSIS): DATA Q2;
MPRINT(ANALYSIS): SET Q1;
MLOGIC(ANALYSIS): %DO loop beginning; index variable I; start value is 1; stop value is 56; by value
is 1.
MLOGIC(ANALYSIS): %LET (variable name is SEGS)
MLOGIC(ANALYSIS): %IF condition &SEGS.<=2.5 is FALSE
MLOGIC(ANALYSIS): %IF condition (&SEGS.>2.5 AND &SEGS.<5.5) is FALSE
MLOGIC(ANALYSIS): %IF condition &SEGS.>=5.5 is TRUE
MLOGIC(ANALYSIS): %PUT &segs.
yr1960
MLOGIC(ANALYSIS): %DO loop index variable I is now 2; loop will iterate again.
MLOGIC(ANALYSIS): %LET (variable name is SEGS)
MLOGIC(ANALYSIS): %IF condition &SEGS.<=2.5 is FALSE
MLOGIC(ANALYSIS): %IF condition (&SEGS.>2.5 AND &SEGS.<5.5) is FALSE
MLOGIC(ANALYSIS): %IF condition &SEGS.>=5.5 is TRUE
***NOTE: Line generated by the macro variable "SEGS".
1 yr1961_R
--------
22
You are confusing IF conditions inside the Macro processor versus inside the Data Step. I think this is what you want.
%macro analysis();
DATA Q2;
SET Q1;
%do i=1 %to &CNT.;
%let segs =%scan(&VARS.,&i.," ");
IF &SEGS.<=2.5 THEN &SEGS._R="FREE";
ELSE IF (&SEGS.>2.5 AND &SEGS.<5.5) THEN &SEGS._R="PARTLY FREE";
ELSE IF &SEGS.>=5.5 THEN &SEGS._R="NOT FREE";
/*%PUT &segs.;*/
%end;
RUN;
%MEND;
%analysis();
Macros write code for you. You were comparing the variable Name to the constant values (using string ordering, no less), not the variable values versus the constant values using numbers.