If you take a longer look at the original posting you will see that “new.” is not the name of a variable, just plain text. After I tried to run this program, I got a little confused myself.
First of all, I don’t think that call execute has anything to do with the problem. The record is not appended to the audit dataset if you invoke the macro like %createdataaudit(audit,"old val","new."), which is the text generated by the call execute statement. See the log below:
[pre]
1159 data audit;
1160 length newval oldval $ 8;
1161 run;
NOTE: Variable newval is uninitialized.
NOTE: Variable oldval is uninitialized.
NOTE: The data set WORK.AUDIT has 1 observations and 2 variables.
NOTE: DATA statement used (Total process time):
real time 0.03 seconds
cpu time 0.01 seconds
1162
1163 %macro createdataaudit(outdata,newval,oldval);
1164
1165 %if &newval ne &oldval %then %do;
1166 %if %sysfunc(exist(&outdata)) %then %do ;
1167 PROC SQL;
1168 INSERT INTO &outdata
1169 SET newval=&newval, oldval=&oldval;
1170 QUIT;
1171 %end;
1172 %end;
1173
1174 %mend createdataaudit;
1175
1176 options mprint mlogic;
1177 %createdataaudit(audit,"old val","new.")
MLOGIC(CREATEDATAAUDIT): Beginning execution.
MLOGIC(CREATEDATAAUDIT): Parameter OUTDATA has value audit
MLOGIC(CREATEDATAAUDIT): Parameter NEWVAL has value "old val"
MLOGIC(CREATEDATAAUDIT): Parameter OLDVAL has value "new."
MLOGIC(CREATEDATAAUDIT): %IF condition &newval ne &oldval is TRUE
MLOGIC(CREATEDATAAUDIT): %IF condition %sysfunc(exist(&outdata)) is TRUE
MLOGIC(CREATEDATAAUDIT): Ending execution.
[/pre]
Here is where I’m getting confused, if the log says that the condition sysfunc(exist(&outdata)) is true, then why is the SQL statement not written to the input stack? If you now invoke the macro without the period, here is the result:
[pre]
1178 %createdataaudit(audit,"old val","new")
MLOGIC(CREATEDATAAUDIT): Beginning execution.
MLOGIC(CREATEDATAAUDIT): Parameter OUTDATA has value audit
MLOGIC(CREATEDATAAUDIT): Parameter NEWVAL has value "old val"
MLOGIC(CREATEDATAAUDIT): Parameter OLDVAL has value "new"
MLOGIC(CREATEDATAAUDIT): %IF condition &newval ne &oldval is TRUE
MLOGIC(CREATEDATAAUDIT): %IF condition %sysfunc(exist(&outdata)) is TRUE
MPRINT(CREATEDATAAUDIT): PROC SQL;
MPRINT(CREATEDATAAUDIT): INSERT INTO audit SET newval="old val", oldval="new";
NOTE: 1 row was inserted into WORK.AUDIT.
MPRINT(CREATEDATAAUDIT): QUIT;
NOTE: PROCEDURE SQL used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
MLOGIC(CREATEDATAAUDIT): Ending execution.
[/pre]
Now, the SQL statement is correctly written to the input stack. The problem must have something to do with the way that the macro processor interprets the period.
Just to make things more confusing, I said earlier that I didn’t think call execute had anything to do with the problem. However, take a look at the log when you do invoke the macro with call execute:
[pre]
1179 data test;
1180 var1_old = 'old val';
1181 var1_new = 'new.';
1182 run;
NOTE: The data set WORK.TEST has 1 observations and 2 variables.
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
1183
1184 data test;
1185 set test;
1186 if strip(var1_old) ne strip(var1_new) then do;
1187 call
1187! execute('%createdataaudit(audit,'||quote(strip(var1_old))||','||quote(strip(var1_new))||');
1187! ');
1188 end;
1189 run;
NOTE: DATA statement used (Total process time):
real time 0.03 seconds
cpu time 0.01 seconds
MLOGIC(CREATEDATAAUDIT): Beginning execution.
MLOGIC(CREATEDATAAUDIT): Parameter OUTDATA has value audit
MLOGIC(CREATEDATAAUDIT): Parameter NEWVAL has value "old val"
MLOGIC(CREATEDATAAUDIT): Parameter OLDVAL has value "new."
MLOGIC(CREATEDATAAUDIT): %IF condition &newval ne &oldval is TRUE
MLOGIC(CREATEDATAAUDIT): %IF condition %sysfunc(exist(&outdata)) is TRUE
MPRINT(CREATEDATAAUDIT): PROC SQL;
MPRINT(CREATEDATAAUDIT): INSERT INTO audit SET newval="old val", oldval="new.";
MPRINT(CREATEDATAAUDIT): QUIT;
MLOGIC(CREATEDATAAUDIT): Ending execution.
NOTE: There were 1 observations read from the data set WORK.TEST.
NOTE: The data set WORK.TEST has 1 observations and 2 variables.
NOTE: CALL EXECUTE generated line.
1 + PROC SQL; INSERT INTO audit SET newval="old val", oldval="new."; QUIT;;
[/pre]
Note that now, the SQL statement is displayed on the mprint lines and the log says that call execute did generate the SQL statement. However, it’s obvious that the statement was never executed. If the statement were executed, there would have been a note in the log pertaining to process time used by the SQL procedure.
Not that it helps explain why the previous code did not work, but by making some simple modifications to the macro and the way that it’s called, you can create a macro that will successfully append the record to the dataset:
[pre]
1190 %macro createdataaudit(outdata,newval,oldval);
1191
1192 %if &newval ne &oldval %then %do;
1193 %if %sysfunc(exist(&outdata)) %then %do ;
1194 PROC SQL;
1195 INSERT INTO &outdata
1196 SET newval="%bquote(&newval)", oldval="%bquote(&oldval)";
1197 QUIT;
1198 %end;
1199 %end;
1200
1201 %mend createdataaudit;
1202
1203 data test;
1204 set test;
1205 if strip(var1_old) ne strip(var1_new) then do;
1206 call execute('%createdataaudit(audit,'||strip(var1_old)||','||strip(var1_new)||');');
1207 end;
1208 run;
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
MLOGIC(CREATEDATAAUDIT): Beginning execution.
MLOGIC(CREATEDATAAUDIT): Parameter OUTDATA has value audit
MLOGIC(CREATEDATAAUDIT): Parameter NEWVAL has value old val
MLOGIC(CREATEDATAAUDIT): Parameter OLDVAL has value new.
MLOGIC(CREATEDATAAUDIT): %IF condition &newval ne &oldval is TRUE
MLOGIC(CREATEDATAAUDIT): %IF condition %sysfunc(exist(&outdata)) is TRUE
MPRINT(CREATEDATAAUDIT): PROC SQL;
MPRINT(CREATEDATAAUDIT): INSERT INTO audit SET newval="old val", oldval="new.";
MPRINT(CREATEDATAAUDIT): QUIT;
MLOGIC(CREATEDATAAUDIT): Ending execution.
NOTE: There were 1 observations read from the data set WORK.TEST.
NOTE: The data set WORK.TEST has 1 observations and 2 variables.
NOTE: CALL EXECUTE generated line.
1 + PROC SQL;
1 + INSERT INTO audit SET newval="old val", oldval="new.";
NOTE: 1 row was inserted into WORK.AUDIT.
1 + QUIT;
NOTE: PROCEDURE SQL used (Total process time):
real time 0.01 seconds
cpu time 0.00 seconds
[/pre]
Even though the above macro does work, I would really like to understand exactly why the original macro failed.