I'm trying validate if a char macro variable contains another substrings in either order.
%let variable = Coop Fin TDC Real Telco;
options mlogic mprint symbolgen;
%Macro Test/minoperator;
%if Coop Fin in &variable %then %put i = 1;
%else %put i = 0;
%mend;
%Test;
Coop Fin in &variable resolves to TRUE, but Coop TDC resolves to FALSE.
Are there anything form to do it, without import order?
You can do a regular expression matching, the logic below ignores the order:
Solution:
%let variable = Coop Fin TDC Real Telco;
options mlogic mprint symbolgen;
%Macro Test/minoperator;
%if %sysfunc(prxmatch('Coop',"&variable.")) & %sysfunc(prxmatch('TDC',"&variable.")) %then %put i = 1;
%else %put i = 0;
%mend;
%Test;
Output:
MLOGIC(TEST): Beginning execution.
SYMBOLGEN: Macro variable VARIABLE resolves to Coop Fin TDC Real Telco
SYMBOLGEN: Macro variable VARIABLE resolves to Coop Fin TDC Real Telco
MLOGIC(TEST): %IF condition %sysfunc(prxmatch('Coop',"&variable.")) & %sysfunc(prxmatch('TDC',"&variable.")) is TRUE
MLOGIC(TEST): %PUT i = 1
i = 1
MLOGIC(TEST): Ending execution.
If you want to check if ANY of the words exist then you need to parse in string and run for each word:
%let variable = Coop Fin TDC Real Telco;
options mlogic mprint symbolgen;
%Macro Test(input) /minoperator;
%local j n str;
%let n=%sysfunc(countw(&input));
%let i=0;
%do j=1 %to &n;
%let str = %scan(&input,&j);
%if &str in &variable %then %let i = 1;
%else %put i = 0;
;
%end;
%put i = &i;
%mend;
%Test(Coop Fin);
%Test(Coop TDC);
If you want all words then you need count the number of times it resolves to true and only output if that is equal to the count.
%let variable = Coop Fin TDC Real Telco;
options mlogic mprint symbolgen;
%Macro Test(input) /minoperator;
%local j n str;
%let n=%sysfunc(countw(&input));
%let i=0;
%do j=1 %to &n;
%let str = %scan(&input,&j);
%if &str in &variable %then %let i = %eval(&i+1);
;
%end;
%if &i=&n %then
%put i = &i;
%else %put i = 0;
;
%mend;
%Test(Coop Fin);
%Test(Coop TDC x);
Related
I'm a beginner in SAS and I am trying to use a macro to import excel files using a conditional loop.
The importing process is based on initial_year ; final_year; initial_month and final_month values.
But it seems the If condition is not working. Can you help please. Thank you.
This is my sas program:
%let path=\\xxxx.yy.pt\aaa$\INFO\;
%let initial_year=2019; %let initial_month=2;
%let final_year=2021; %let final_month=1;
%Macro import_loop;
%if &final_month >= &initial_month %then %do;
%DO x = &initial_year %TO &final_year;
%DO i = &initial_month %TO &final_month;
%if &i <=9 %then %let anomes=&x.0&i;
%else %let anomes=&x&i ;
proc import datafile="&path&x\Farmacias_EA_&anomes..xlsx"
out=Farmacias_EA_&anomes REPLACE dbms=xlsx;
run;
data Farmacias_EA_&anomes;
set Farmacias_EA_&anomes;
Data_anomes=&anomes;
run;
%end;
%end;
%else %do
%DO x = &initial_year %TO &final_year-1;
%DO i = &initial_month %TO 12;
%if &i <=9 %then %let anomes=&x.0&i;
%else %let anomes=&x&i ;
proc import datafile="&path&x\Farmacias_EA_&anomes..xlsx"
out=Farmacias_EA_&anomes REPLACE dbms=xlsx;
run;
data Farmacias_EA_&anomes;
set Farmacias_EA_&anomes;
Data_anomes=&anomes;
run;
%end;
%end;
%DO x = &final_year %TO &final_year;
%DO i = 1 %TO &final_month;
%if &i <=9 %then %let anomes=&x.0&i;
%else %let anomes=&x&i ;
proc import datafile="&path&x\Farmacias_EA_&anomes..xlsx"
out=Farmacias_EA_&anomes REPLACE dbms=xlsx;
run;
data Farmacias_EA_&anomes;
set Farmacias_EA_&anomes;
Data_anomes=&anomes;
run;
%end;
%end;
%end;
%mend import_loop;
%import_loop
Just treat your dates like dates and the looping will be much easier.
%macro import(from,to);
%local start end offset yymm year ;
%let start=%sysfunc(inputn(&from.01,yymmdd8.));
%let end=%sysfunc(inputn(&to.01,yymmdd8.));
%do offset=0 %to %sysfunc(intck(month,&start,&end));
%let yymm=%sysfunc(intnx(month,&start,&offset),yymmn6.);
%let year=%substr(&yymm,1,4);
proc import datafile="&path.&year.\Farmacias_EA_&yymm..xlsx"
out=Farmacias_EA_&yymm. REPLACE dbms=xlsx
;
run;
data Farmacias_EA_&yymm.;
set Farmacias_EA_&yymm.;
Data_anomes=&yymm.;
run;
%end;
%mend import ;
%let path=\\xxxx.yy.pt\aaa$\INFO\;
%import(201902,201201);
Do you really want the variable DATA_ANOMES to have numbers like 201,902 ? Why not either store it as a string like "201902" or an actual date value like "01FEB2019"d ?
I'm encountering problems when I use the CALL SYMPUT function inside a if-then loop in SAS.
%LET food=kebab;
DATA _NULL_;
IF &food.=pizza THEN DO;
CALL SYMPUT('price',12);
CALL SYMPUT('fat',5);
END;
ELSE IF &food.=kebab THEN DO;
CALL SYMPUT('price',6);
CALL SYMPUT('fat',4);
END;
RUN;
%put &food.;
%put &price.;
%put &fat.;
The variables actually take these values :
food = kebab ; price = 12 (instead of desired value 6) ; fat = 5 (instead of 4)
Thanks in advance for any explanation.
Because you're using a data step, your IF statements need quotes. If it was %IF then your code would be closer to correct.
%LET food=kebab;
DATA _NULL_;
IF "&food." = "pizza" THEN DO;
CALL SYMPUT('price',12);
CALL SYMPUT('fat',5);
END;
ELSE IF "&food." = "kebab" THEN DO;
CALL SYMPUT('price',6);
CALL SYMPUT('fat',4);
END;
RUN;
%put &food.;
%put &price.;
%put &fat.;
Another option is full macro logic, this will work in SAS 9.4M5+
%LET food=kebab;
%IF &food.=pizza %THEN %DO;
%let price = 12;
%let fat=5;
%END;
%ELSE %IF &food.=kebab %THEN %DO;
%let price = 6;
%let fat=4;
%END;
%put &food.;
%put &price.;
%put &fat.;
EDIT: If you're not on SAS 9.4M5+ which supports open macro code you need to wrap your logic in a macro.
%macro create_variables();
%global price fat;
%LET food=kebab;
%IF &food.=pizza %THEN %DO;
%let price = 12;
%let fat=5;
%END;
%ELSE %IF &food.=kebab %THEN %DO;
%let price = 6;
%let fat=4;
%END;
%put &food.;
%put &price.;
%put &fat.;
%mend;
%create_variables();
I need help on comparing two macro variable dates. Below is the code. You can see by the log that MINDT_AS_DATE_MINUS_ONE_DT1 is 23JUL2012 and TESTDT1 is 01JAN2013. However, when comparing SAS says 23JUL2012 <01JAN2013. is FALSE. I am very confused. Thanks
%let TESTDT=2013-01-01;
%let TESTDT1=%sysfunc(inputn(&TESTDT, yymmdd10.), date9.);
%LET MINDT = 2012-07-23;
%LET MINDT_AS_DATE = %SYSFUNC(INPUTN(&MINDT., YYMMDD10.));
%LET MINDT_AS_DATE_MINUS_ONE = %SYSFUNC(INTNX(MONTHS, &MINDT_AS_DATE., -1));
%LET MINDT_AS_DATE_MINUS_ONE_DT = %SYSFUNC(INPUTN(&MINDT., YYMMDD10.));
data _null_;
MINDT_AS_DATE_MINUS_ONE_DT=&MINDT_AS_DATE_MINUS_ONE_DT.;
call symput('MINDT_AS_DATE_MINUS_ONE_DT1',put(MINDT_AS_DATE_MINUS_ONE_DT,date9.));
run;
%macro intermediate;
%if &MINDT_AS_DATE_MINUS_ONE_DT1.<&TESTDT1. %then
%do;
%PUT this is true;
%end;
%else
%do;
%PUT this is false;
%end;
%mend intermediate;
%intermediate;
Not working in LOG, See:
SYMBOLGEN: Macro variable MINDT_AS_DATE_MINUS_ONE_DT1 resolves to 23JUL2012
SYMBOLGEN: Macro variable TESTDT1 resolves to 01JAN2013
MLOGIC(INTERMEDIATE): %IF condition &MINDT_AS_DATE_MINUS_ONE_DT1.<&TESTDT1. is FALSE
MLOGIC(INTERMEDIATE): %PUT this is false
this is false
Props to Reeza
%macro intermediate;
%if %sysevalf("&MINDT_AS_DATE_MINUS_ONE_DT1."d < "&TESTDT1."d) %then %do;
%PUT this is true;
%end;
%else %do;
%PUT this is false;
%end;
%mend intermediate;
%intermediate;
I'm triying to run the next Macro, and I have hoped the expression "&minimum_age le &age le &maximum_age" take a false value, so output at log should be: "Under the required age", but evaluation is take value true. I really do not understand it.
%let date_of_birth = '11may2008'd;
%let minimum_age = 18;
%let maximum_age = 72;
%let age = %sysfunc(int(%sysfunc(yrdif(&date_of_birth,%sysfunc(today()),'AGE'))));
%put &= &age;
%Macro test;
%if not(&minimum_age le &age le &maximum_age) %then %put Under the required age;
%Mend;
%test;
Evaluation :
&minimum_age le &age is evaluated to "0"
then
0 le &maximum_age is evaluated to 1
so not(1) = 0
and finally , %put Under the required age is not executed
Change to :
%let date_of_birth = '11may2008'd;
%let minimum_age = 18;
%let maximum_age = 72;
%let age = %sysfunc(int(%sysfunc(yrdif(&date_of_birth,%sysfunc(today()),'AGE'))));
%put &= &age;
%Macro test;
%put %eval(&minimum_age ge &age);
%put %eval(&age ge &maximum_age);
%if &minimum_age ge &age or &age ge &maximum_age %then %put Under or up to the required age;
%Mend;
%test;
I can't figure out how to pass to a conditional macro the values of a dataset variable. Let's say we HAVE:
data HAVE;
input id name $ value ;
datalines;
1 pluto 111
2 paperino 222
3 trump 333
4 topo 444
;
run;
I would like to use dataset variable name inside a sas conditinal macro to make other IF conditions.
What i mean is to use this code with another IF step before the conditional macro (or inside the conditional macro)
options minoperator mlogic;
%macro test(var) / mindelimiter=',';
%if &var in(pippo,pluto) %then %do; "if &var"n = name; end;
%else %do;"mod &var"n = name;end;
%mend test;
data want;
set have;
%test(pippo);
%test(arj);
%test(frank);
%test(pluto);
%test(george);
run;
For example:
options minoperator mlogic;
%macro test(var) / mindelimiter=',';
if name = &var then do;
%if &var in(pippo,pluto) %then %do "if &var"n = name; %end;
%else %do; "mod &var"n = name; end;
end;
%mend test;
but the IF name = &var is always true... there's some problem with using the name dataset variable inside the macro.
EDIT AFTER first answer
example code of conditioning inside the conditional macro:
%macro test(var) / mindelimiter=',';
%if &var in(pippo pluto) %then %do;
if name = 'pluto' then ifif_&var. = name;
if_&var. = name;
%end;
%else %do;
mod_&var. = name;
%end;
%mend test;
it' just an example off course it's almost useless.
There's nothing inherently wrong with using it that way, though you have some errors in your code.
%macro test(var) / mindelimiter=',';
if name = "&var" then do;
%if &var in(pippo pluto) %then %do; if_&Var. = name; %end;
%else %do; mod_&var. = name; %end;
end;
%mend test;
That works, or at least as far as I can tell works for what you want.
Looks like you want to generate code from your data.
data _null_;
set have end=eof;
if _n_=1 then call execute('data want;set have;');
call execute(cats('%nrstr(%test)(',name,')'));
if eof then call execute('run;');
run;