Any idea why this stop execution code doesn't work?
There is no observation in table1, but proc print still runs.
%macro execute (inputdata=work.table1);
data _null_;
if 0 then set &inputdata. nobs=n;
call symputx('totobs',n);
stop;
run;
%if &totobs. = 0 %then %put exit;
%else %do;
%put execute further;
%end;
%mend execute;
%execute(inputdata=work.table1)
proc print data= work.table1;
run;
Your Proc PRINT occurs after the macro execution, and thus there is nothing preventing the proc from being submitted. The %put exit only causes a message from the macro system to be displayed in the log window.
There are some tricky things you could do, but shouldn't
definitely not this: have the macro emit source code ;* when there are no observations. The semi-colon asterik (;*) will cause a null statement (or complete an open one), and then start a comment statement in the source code (being handled by the submit processor) that ends at the next semi-colon. %if &totobs. = 0 %then %str(;*);
When totobs is zero the submit processor will see source code
;*proc print data= work.table1;
maybe this: halt all further execution of the currently submitted source code. Inside the macro an %abort cancel will do this.
%if &totobs. = 0 %then %abort cancel;
The best answer is the question "What do you want to happen?"
Related
This code will be part of process in SAS data Integration Studio.
I want to achieve something like:
%macro conditional_start();
%let check_condition = 0;
%if check_condition eq 0 %then %do;
%send_email_that_condition_has_been_met(); /* this I have made */
/*Below run some kind of built-in macro probably, to stop execution of the whole code below */
%end;
%mend;
/*More macros end code I don't want to execute*/
I cannot pack everything below in big "if" statement because they are built in blocks.
Is it possible?
Thanks in advance!!
Have you tried to put your code into "precode" (leave macro open) and "postcode" (rest of the macro) sections of your job's properties?
For example:
precode:
%macro the_whole_job();
postcode:
%mend the_whole_job;
%macro conditional_start();
%let check_condition = 0;
%if check_condition eq 0 %then %do;
%send_email_that_condition_has_been_met(); /* this You have made */
/*do some kind of built-in macro meaning failure, not executing the whole code above*/
%end;
%else %do;
%the_whole_job;
%end;
%mend;
I am getting a generic 'Statement not valid or out of order' message with the below:
%macro test;
data _null_;
%if %sysfunc(fileexist("C:\report_201809.xlsx")) = 1 %then %do;
rc=%sysfunc(rename("C:\report_201809.xlsx",
"C:\report_201809.xlsx"_old.xlsx",'file'));
%end;
%mend;
%test;
The code below should get you what you need. While you can use %if statements in a data step you generally won't need to. I'm guessing the error is coming from the %sysfunc function around the fileexist and rename functions. %sysfunc allows you to call data step functions outside of a data step so it is not needed here.
%macro test;
data _null_;
if fileexist("C:\file.txt") then do;
rc = rename("C:\file.txt", "C:\file2.txt", 'file');
end;
run;
%mend;
Alternatively, you could use an X Command that allows you to execute Windows commands. You could replace the rename function with the following statement.
x move C:\file.txt C:\file2.txt;
Remove the DATA _NULL_ or proceed per #J_Lard.
Macro arguments used in %sysfunc invoked function calls are implicitly quoted and do not need additional ' or "
%macro test;
%local rc;
%if %sysfunc(fileexist(C:\report_201809.xlsx)) = 1 %then %do;
%let rc = %sysfunc(rename(C:\report_201809.xlsx,C:\report_201809_old.xlsx,file));
%end;
%test;
You original code may have worked (by way of non-obvious side effect) if the filename "C:\report_201809.xlsx"_old.xlsx" (having an extraneous ") was corrected to "C:\report_201809_old.xlsx"
I have to different statements in one code. For example:
First:
data step2;
set ste1;run;
proc print data=step2;quit;
Second:
data step6;
set ste5;run;
proc print data=step5;quit;
Is it possible to choose by PROMPT variable which one of them I need to Execute?
Assuming you mean a stored process prompt variable, you can simply build a macro:
%macro choose;
%if &mypromptvar=1 %then %do;
data step2;
set ste1;run;
proc print data=step2;quit;
%end;
%if &mypromptvar=2 %then %do;
data step6;
set ste5;run;
proc print data=step5;quit;
%end;
%mend;
%choose;
where mypromptvar is the name of your promptvariable...
Could someone please explain why it is happening?
I'm trying to find objects dependencies tree in a DB.
Let's say view5 is a view sits on top view4 which sits on top view1.
Also,
view3 sits on top view2 sits on top view1.
So,
the when I query the macro for view1, I should get back view4, view5, view2 and view3.
This is the macro:
%macro dependencies(obj=);
%let dependent_objectname =;
proc sql noprint;
select "'"||trim(dependent_objectname)||"'"
into :dependent_objectname separated by ", "
from &_input.
where src_objectname in (&obj.);
quit;
%put &dependent_objectname.;
%let dependent_objectname = (&dependent_objectname.);
%put &dependent_objectname.;
%if %length("&dependent_objectname")>0 %then
%dependencies(obj = &dependent_objectname.);
%mend dependencies;
%let source = 'ditemp.depend_test1';
%put &source.;
%dependencies(obj = &source.);
First iteration works well,
I get the objects sit on top depend_test1
in a form of "('ditemp.depend_test2','ditemp.depend_test3')"
then I'm checking for the length of variable dependent_objectname (greater than zero)
and calling the macro again,
only it never stops...
I see a couple problems.
The statement:
%if %length("&dependent_objectname")>0 %then %do;
will always return true, even if the value of &dependent_objectname is null. Because the quotes are part of the value in the macro language. You probably want:
%if %length(&dependent_objectname)>0 %then %do;
That test for nullness usually works. Or see this paper for better methods. http://support.sas.com/resources/papers/proceedings09/022-2009.pdf
Before that, the statement:
%let dependent_objectname = (&dependent_objectname.);
is adding parentheses to your value. So again, even if &dependent_objectname were null, it would be () after this. It looks like you don't need these parentheses, so I would skip this statement.
I would also add:
%local dependent_objectname ;
to the top of the macro. That way each invocation of the macro will have its own local macro variable, rather than having them all use the macro variable created in the first iteration (or worse yet, all use a global macro variable).
You have sensibly added %PUT statements to help with debugging. I would expect they would show that the value of &dependent_objectname is always non-null as currently written. You could also add:
%put The length is: %length(&dependent_objectname.) ;
Since you are using an SQL query to generate the dependent list you can use the automatic variable SQLOBS in your test to break the recursion.
%if &sqlobs %then %do;
%dependencies(obj = &dependent_objectname.);
%end;
Also do NOT use a comma as the delimiter between the items listed in the OBJ parameter. The IN operator in SAS doesn't need them and they will cause trouble in the macro call.
select * from sashelp.class where name in ('Alfred' 'Alice') ;
So your macro could look like this:
%macro dependencies(object_list);
%local dependent_list ;
proc sql noprint;
select catq('1as',dependent_objectname)
into :dependent_list separated by ' '
from &_input.
where src_objectname in (&object_list)
and dependent_objectname is not null
;
quit;
%put Dependent Objects of (&object_list) = (&dependent_list);
%if &sqlobs %then %dependencies(&dependent_list);
%mend dependencies;
And here is a test case.
%let _input=sample;
data sample;
length src_objectname dependent_objectname $41 ;
input (_all_) (:) ;
cards;
object1 object2
object2 object3
object2 object4
;;;;
%dependencies('object1');
I have a dataset naming error_table as follows. All the variables are character
Errorno Error Resolution
001 login check
002 datacheck check
I wanted a logic that executes a sas program If the Errorno is not in 001 and 002. Else stop execution and display the error_table.
I tried the following
%macro test();
proc sql;
select trim(Error_No) into: num from error_table;
quit;
%if &num. not in ("001","002") %then %do;
%include "/path/dev/program.sas";
%end;
%else %do;
proc print data = error_table;
run;
%end;
%mend;
%test;
But, it is throwing an error.
Can anyone please correct the logic.
You need to watch out for the case when the SELECT returns zero rows. You should set a default value to the macro variable NUM.
Is your dataset variable numeric or character? Use the TRIMMED or SEPARATED BY clause instead of the TRIM() function to prevent spaces in the macro variable that is generated by the INTO clause.
%let num=NONE;
select Error_No into: num trimmed from error_table;
Remember that to the macro processor everything is a string so don't but quotes around the values you are trying to match unless they are actually part of the value.
%if NOT (&num. in (001,002)) %then %do;
Also to use the IN operator in macro code you need to make sure you have set the MINDELIMITER option.
I would sugest moving condition with error codes to proc sql.
proc sql;
select count(*) into :num_errors
from error_table
where Errorno in ("001", "002");
quit;
Then in macrovariable you have number of errors that are 001 or 002.
Next step is to check macro-condition:
%if &num_errors. > 0 %then %do;
%include "/path/dev/program.sas";
%end;
%else %do;
proc print data = error_table;
run;
%end;
%mend;