I have the following code in a macro:
...
data HE2update (drop=sum_values n_values);
set dst_end_update;
by short_date HE;
%if HE=2 or 3 %then %do;
sum_values+value;
n_values+1;
%if HE=2 %then delete;
%else %if HE=3 %then %do;
value = round(sum_values/n_values);
HE=2;
%end;
%end;
%if HE>3 %then HE=HE-1;
%else HE;
run;
I am getting the following Error: ERROR 22-322: Syntax error, expecting one of the following: !, !!, &, *, **, +, -, /, <, <=, <>, =, >, ><, >=, AND, EQ, GE, GT, IN,
LE, LT, MAX, MIN, NE, NG, NL, NOTIN, OR, ^=, |, ||, ~=.
The error seems to be with the last if/then/else statement I don't see what I need to correct. Any help would be greatly appreciated.
The macro processor is used to generate code, not operate on data.
Your first %IF is testing whether the string HE is equal to 2 (which is false) and then OR ing the result with the number 3 (which is true) so the test is true which means these two statements are generated to include in your data step.
sum_values+value;
n_values+1;
The other two %IF tests in that %IF/%THEN/%DO/%END block are both false since the string HE does not equal either the digit 2 or the digit 3.
Then finally you test if the string HE is larger than the digit 3 which is TRUE since H is after 3 in the ASCII collating sequence. This means your program will generate the code
HE=HE-1
Notice that there is no closing semi-colon for that assignment statement. The semi-colon in the program marks the end of the %IF/%THEN statement.
So the code you generated is:
data HE2update (drop=sum_values n_values);
set dst_end_update;
by short_date HE;
sum_values+value;
n_values+1;
HE=HE-1 run;
That last assignment statement is not valid SAS syntax. Plus there is no RUN; to end the data step.
I don't think you need macro logic here at all.
data HE2update (drop=sum_values n_values);
set dst_end_update;
by short_date HE;
if HE in (2, 3) then do;
sum_values+value;
n_values+1;
if HE=2 then delete;
else if HE=3 then do;
value = round(sum_values/n_values);
HE=2;
end;
end;
if HE>3 then HE=HE-1;
run;
Related
Why is this macro not working?
%MACRO Cerved_recap;
%let i=2;
%DO i = 2 %TO &oggi.;
%let ieri = %sysevalf(&i.-1);
data work.initial_db_cerved;
set work.initial_db_cerved;
length esito_&i. $ 10;
format esito_&i. $char20.;
%if ENCOURS_TOTAL_&i. < ENCOURS_TOTAL_&ieri. %then %do; esito_&i.='total_out';
%end;
%else %do; esito_&i.= '-';
%end;
run;
%end;
%MEND Cerved_recap;
%Cerved_recap;
Here is a technical answer, to get a real answer explain in words what you are trying to do, and perhaps show an example of the working SAS code you are trying to use the macro to generate.
Since you set I to a digit string like 2 and set IERI to a digit string like 1 the test in your %IF statement will usually be false. It is comparing a string like ENCOURS_TOTAL_2 to another string like ENCOURS_TOTAL_1 and since the beginning of those two strings are exactly the same it just like comparing the digit 2 to the digit 1. The test will only be true when I has a value that is a power of 10 (10 100 1000 etc) because then you are comparing a string that starts with the digit 1 to a string that starts with the digit 9.
Perhaps you wanted to compare the values of SAS variables with those names?
If so then use actual SAS statements instead of macro statements.
if ENCOURS_TOTAL_&i. < ENCOURS_TOTAL_&ieri. then esito_&i.='total_out';
else esito_&i.= '-';
I have this macro that doesn't resolve even if the logic seems to work. I'm a beginner sas user so the code might look a little messy.
%let macro1 = 1600;
%let macro2 = 1300;
%if '¯o1.' > '¯o2.' %then %do;
%let macro3 = increase;
%else %if '¯o1.' < '¯o2.' %then %do;
%let macro3 = decrease;
%else %if '¯o1.' = '¯o2.' %then %do;
%let macro3 = stability;
%end;
when I run the code, there are no errors but macro3 does not resolve and it looks something like:
"There is a ¯o3. between 1600 and 1300"
You are missing %END; statements for the %DO; statements. Do you really need the %DO; statements? You don't appear to be trying to run multiple statements when the condition is true.
The macro processor will ignore macro triggers that are inside quoted strings that are bounded by single quote characters. So the result of your tests will always be that the string '¯o1' is less than the string '¯o2' because the digit 1 comes before the digit 2 in lexicographical ordering.
Either remove the quotes completely or replace them with double quote characters.
Without the quotes the implied %EVAL() macro function call will compare the strings 1600 and 1300 as integer numbers. With the quotes then %EVAL() will compare the string "1600" and "1300" as character strings.
So if the values of MACRO1 and MACRO2 are supposed to be numbers then do not include the quotes in the %IF conditions. Otherwise values like "1200" will be less that values like "800" becuase 8 is larger than 1.
You also have to wrap the whole sequence of %IF/%THEN/%ELSE/%IF inside a macro definition, if it is not already inside of a macro definition, because you cannot have nested %IF in open code.
%macro testit;
%let macro1 = 1600;
%let macro2 = 1300;
%if ¯o1. > ¯o2. %then %let macro3 = increase;
%else %if ¯o1. < ¯o2. %then %let macro3 = decrease;
%else %let macro3 = stability;
%put &=macro3 ;
%mend testit;
%testit;
And if &MACRO1 and &MACRO2 are not INTEGER values then you will need to explicitly use %SYSEVALF() to compare them.
%let macro1 = 16.50;
%let macro2 = 13.00;
%if %sysevalf(¯o1. > ¯o2.) %then ....
I have inherited macro in which the below block does not seem to be resolved. The macro is supposed to conditionally select the logical operations based on the date values. If the %if conditions are satisfied, they should print the macro variables mentioned in the %put statement, which in-turn become part of the if condition. If the condition %if %length(&datein.)=10 OR %length(ST_&date.)=10 is satisfied, it would print the first %put statement else the second %put statement would be printed. Same logic applies to the second %if statement.
The macro is supposed to be run inside a data step. The logical operator AND is being considered as a variable and I'm getting a note NOTE: Variable AND is uninitialized.
I tried to balance the if condition by adding the open and closed parenthesis mentioned in below code. Tried to change the structure of the if condition to separate the first and the second condition, but doesn't seem to work. I assuming that the logical operator AND cannot be used as it is in the %if %then %else statement.
%macro test_date(date=, comp1=, comp2=, label=);
if &datein. ne "" and ST_&date. ne "" then do;
if (%if %length(&datein.)=10 OR %length(ST_&date.)=10 %then %put ST_&date._10 &comp1. datein_10; %else %put ST_&date._19 &comp1. datein_19;
AND %if %length(&datein.)=10 OR %length(ED_&date.)=10 %then %put datein_10 &comp2. ED_&date._10; %else %put datein_19 &comp2. ED_&date._19;)
then EPOCH=&label.;
end;
%mend test_date;
%test_date(date=SCREEN, comp1= le, comp2= le, label='SCREEN');
You will probably need to adapt this a bit, but it should be helpful in clearifying the logic of it. The code below checks the length of macro variables and inserts data step code based on this length. It will also print some values to the log, but that doesn't affect results. I've included some simple data step examples to illustrate how it works.
%macro test_date(date=, comp1=, comp2=, label=);
%if &datein. ne and &&ST_&date. ne %then %do;
%if %length(&datein.)=10 OR %length(&&ST_&date.)=10 %then %do;
/* Insert data step code */
if variable1=1 then epoch="First condition";
else epoch="firstelse";
/* Print to log*/
%put &&ST_&date. &comp1. &datein.;
%end;
%else %if %length(&datein.)=10 OR %length(&&ED_&date.)=10 %then %do;
if variable1=0 then epoch="Second condition";
else epoch="secondelse";
%end;
%end;
%mend test_date;
/* Macro variables given values of length 10. Outer if and first condition in do block holds.*/
%let datein=0123456789;
%let st_screen=0123456789;
%let ed_screen=0123456789;
data test1;
variable1=1;
%test_date(date=SCREEN, comp1= le, comp2= le, label='SCREEN');
run;
data test2;
variable1=0;
%test_date(date=SCREEN, comp1= le, comp2= le, label='SCREEN');
run;
/* Macro variables given values of length 9 and 10. Outer if and else condition in do block holds.*/
%let datein=012345678;
%let st_screen=012345678;
%let ed_screen=0123456789;
data test3;
variable1=1;
%test_date(date=SCREEN, comp1= le, comp2= le, label='SCREEN');
run;
data test4;
variable1=0;
%test_date(date=SCREEN, comp1= le, comp2= le, label='SCREEN');
run;
/* Macro variables are empty. Outer if is false. The macro does nothing. */
%let datein=;
%let st_screen=;
%let ed_screen=;
data test5;
variable1=1;
%test_date(date=SCREEN, comp1= le, comp2= le, label='SCREEN');
run;
data test6;
variable1=0;
%test_date(date=SCREEN, comp1= le, comp2= le, label='SCREEN');
run;
Your program does not make any sense. If we ignore the %IF statements that are just potentially generating messages to the LOG your macro is generating this SAS code:
if &datein. ne "" and ST_&date. ne "" then do;
if ( AND ) then EPOCH=&label.;
end;
Since you are using the variable AND as the condition for the IF statement SAS will assume that it is a numeric variable and test whether its value is non-zero and non-missing. If there is no variable named AND then its value will be missing so the value of EPOCH will never be changed.
If you want the macro to do those tests of macro variable lengths then pull that macro logic out of the middle of the SAS code you are trying to generate.
Let's look at the first %IF/%THEN statement.
%if %length(&datein.)=10 OR %length(ST_&date.)=10
%then %put ST_&date._10 &comp1. datein_10;
%else %put ST_&date._19 &comp1. datein_19;
So you are testing if the length of the macro variable DATEIN is 10 bytes or the length of the macro variable DATE is 7 bytes (the constant text ST_ will always be 3 bytes long).
Try again. This code will not work. It is a stupid code but still do not work.
data work.colnames;
input cols $;
cards;
U1
B1
;
run;
data work.test;
input rp_U1 $ rp_B1 $;
cards;
col1 col2
;
run;
%macro maketest;
proc sql;
select cols
into :col separated by " "
from colnames;
quit;
%do i=1 %to 2;
%let c = %qscan(&col,&i);
%put rp_&c;
proc sql;
create table test&i as
select
rp_&c
from work.test;
quit;
%end;
%mend;
%maketest;
I do get this error:
ERROR 22-322: Syntax error, expecting one of the following: !, !!, &, *, **, +, ',', -, '.', /, <, <=, <>, =, >, >=, ?, AND, AS,
CONTAINS, EQ, EQT, GE, GET, GT, GTT, LE, LET, LIKE, LT, LTT, NE, NET, OR, ^=, |, ||, ~=.
Which I find strange is if I try to get the columns without the rp_ this code works find. Also change
select
rp_&c
to
select
&c
The macro quoting you introduced by using %QSCAN() function instead of the %SCAN() function is probably causing trouble for the SAS parser.
In your code the macro variable C gets assigned the values of U1 and B1, respectively. But the values are macro quoted. So when the parser sees rp_&c it thinks that those are two separate tokens so it treats it like token rp_ followed by the token U1 instead of a single token of rp_U1.
You should not need to quote a string that will be part of a variable name, so you should change
%let c = %qscan(&col,&i);
to
%let c = %scan(&col,&i);
But if you do need to have the macro quoting then you can use the %unquote() function to remove it. So change
select rp_&c
to
select %unquote(rp_&c)
I need to create a prompt. Actually I created another two with no problem, but one of the variable is different while I was creating prompt. I needed to do macro with that as below:
%macro param_list;
%global
list_selected
;
%let i=1;
%let p_lst_tmp = %scan(&VID,&i);
%do %while(&p_lst_tmp ne);
%let list_selected = &list_selected "%scan(&VID,&i)";
%let i = %eval(&i+1);
%let p_lst_tmp = %scan(&VID,&i);
%end;
%put list_selected = &list_selected;
%mend;
Then in the code I created
PROC SQL;
CREATE TABLE Student_Pre AS
SELECT t1.personid LABEL="PIDM" AS PIDM,
t1.V_ID as VID,
t1.FIRST_NAME
FROM ENROLL.Student_Dim t1
WHERE t1.v_id = &list_selected
ORDER BY t1.personid;
QUIT;
But this code gives an error, ERROR 22-322: Syntax error, expecting one of the following: ;, !, !!, &, (, , *, +, -, '.', /, <, <=, <>, =, >, >=, AND, EQ, EQT, EXCEPT, GE, GET, GROUP, GT, GTT, HAVING, INTERSECT, LE, LET,
LT, LTT, NE, NET, NOT, OR, ORDER, OUTER, UNION, ^, ^=, |, ||, ~, ~=.
ERROR 76-322: Syntax error, statement will be ignored.
How should I change the code?