BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
kmardinian
Quartz | Level 8

Hi, I created this macro below and have been running it with datasets that contain observations, but as soon as one dataset has 0 observations that fit the criteria, it seems that the macro spits out numbers from the dataset that was run previously. Here is my code below

 

%macro num (vorder, var);

data final_&vorder;
   set t5;
 if &var ne .;
run;


 proc summary data=final_&vorder completetypes chartype missing noprint;
 class outcome trt;
 types outcome*trt;
 output out=discrete;
 run;

proc freq data=discrete;
 by _type_;
 tables outcome*trt/norow nopercent;
 weight _freq_/zeros;
 ods output crosstabfreqs_&vorder=crosstabfreqs_&vorder (where=(_type_2='01' or _type_2='11'));
 run;

data CrossTabFreqs_&vorder /*(keep=vname rowlabel cell _level_ idlabel _type_)*/;
length vname $32 rowlabel $100 cell $32 idlabel $256;
set CrossTabFreqs;
vname =vnamex(scan(table,2,' '));
rowlabel=vvalueX(vname);
cell=cats(Frequency);
format colPercent 8.1;
set bign key=trt_dec/unique;
idlabel=cat(strip(vvalue(trt_dec)),' ^ ',cat('(N = ',bign,')'));
run;

 

Is there a way to create another criteria that tells SAS to return nothing if there are no observations in the dataset? Thank you, any help is much appreciated!

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

@kmardinian wrote:

Hi, I created this macro below and have been running it with datasets that contain observations, but as soon as one dataset has 0 observations that fit the criteria, it seems that the macro spits out numbers from the dataset that was run previously. Here is my code below

 ....


You can test in the data step that is filtering the data and set a macro variable that you can use to control what code to run.

I simple way is to use WHERE instead of IF and the END= option on the SET statement.  

data final_&vorder;
  if eof then call symputx('nobs',_n_-1);
  set t5 end=eof;
  where &var ne .;
run;

Make sure to put the CALL SYMPUTX() call BEFORE the SET statement. SAS data steps normally stop when they read past the end of the input data. So for an empty input set the statements after the SET statement never run.

 

You could then use the value of &NOBS to control your code.

%if &nobs > 0 %then %do;
* code to process the data ;
%end;
%else %do;
* code to run when input set is empty ;
%end;

View solution in original post

8 REPLIES 8
ballardw
Super User

@kmardinian wrote:

Hi, I created this macro below and have been running it with datasets that contain observations, but as soon as one dataset has 0 observations that fit the criteria, it seems that the macro spits out numbers from the dataset that was run previously. Here is my code below

 

%macro num (vorder, var);

data final_&vorder;
   set t5;
 if &var ne .;
run;


 proc summary data=final_&vorder completetypes chartype missing noprint;
 class outcome trt;
 types outcome*trt;
 output out=discrete;
 run;

proc freq data=discrete;
 by _type_;
 tables outcome*trt/norow nopercent;
 weight _freq_/zeros;
 ods output crosstabfreqs_&vorder=crosstabfreqs_&vorder (where=(_type_2='01' or _type_2='11'));
 run;

data CrossTabFreqs_&vorder /*(keep=vname rowlabel cell _level_ idlabel _type_)*/;
length vname $32 rowlabel $100 cell $32 idlabel $256;
set CrossTabFreqs;
vname =vnamex(scan(table,2,' '));
rowlabel=vvalueX(vname);
cell=cats(Frequency);
format colPercent 8.1;
set bign key=trt_dec/unique;
idlabel=cat(strip(vvalue(trt_dec)),' ^ ',cat('(N = ',bign,')'));
run;

 

Is there a way to create another criteria that tells SAS to return nothing if there are no observations in the dataset? Thank you, any help is much appreciated!


One easy solution to prevent reusing a data set is to delete it before the new version should be created.

Assuming that the data set you may have issues with is the set DISCRETE as the output from Proc Summary then adding this somewhere before the proc summary step:

proc datasets library=work;
delete discrete;
run;

would prevent re-use. If the data set does not exist there is no error but you do get messages like:

 

NOTE: The file WORK.DISCRETE (memtype=DATA) was not found, but appears on a DELETE statement.

in the log.

 

The code for checking 1) existence and 2) numbers of observations and handling the result is a bit longer.

 

More specific details about which sets to ignore would be helpful.

s_lassen
Meteorite | Level 14
Instead of using the DATASETS procedure, I would recommend the resurrected DELETE procedure. That way, you do not get the library listing, and PROC DELETE is also faster, as it does not scan the whole library.
Reeza
Super User

See the example macros here, to extend your macro to appropriately handle the 0 case scenario. 

 

https://communities.sas.com/t5/SAS-Communities-Library/SAS-9-4-Macro-Language-Reference-Has-a-New-Ap...

 

Most likely Example 13 or a combo of 8/9 depending on what exactly you're trying to do. 

 

 

kmardinian
Quartz | Level 8

If I were to use this code from Example 13:

 

data one;
x=1;
run;
data two;
stop;
run;

%macro drive(dsn);
%let dsid=%sysfunc(open(&dsn));
    
 %if &dsid ne 0 %then %do;
  %let cnt=%sysfunc(attrn(&dsid,nlobs));
  %let rc=%sysfunc(close(&dsid));
   %if &cnt ne 0 %then %do;
    proc print data=&dsn;
     title "This is data from data set &dsn"; 
    run;
   %end;
   %else %do;
    data _null_;
     title;
     file print;
     put _page_;
     put "Data set &dsn is empty.";
    run;
   %end;
 %end;
 %else %put &dsn cannot be open.;
   

How would i then transition into my own macro? I'm sorry, I'm new to using macros so am unfamiliar with some of the concepts

kmardinian
Quartz | Level 8

Would it work this way?

 

%macro num (vorder, var);

data &dsn;
   set t5;
 if &var ne .;

output data=final_&vorder;
run;


 proc summary data=final_&vorder completetypes chartype missing noprint;
 class outcome trt;
 types outcome*trt;
 output out=discrete;
 run;

Reeza
Super User
You'd put your code in between the %else %do/%end section to allow you to have that code run. Read the detailed explanation of the macro below, that explains it step by step.
Tom
Super User Tom
Super User

@kmardinian wrote:

Hi, I created this macro below and have been running it with datasets that contain observations, but as soon as one dataset has 0 observations that fit the criteria, it seems that the macro spits out numbers from the dataset that was run previously. Here is my code below

 ....


You can test in the data step that is filtering the data and set a macro variable that you can use to control what code to run.

I simple way is to use WHERE instead of IF and the END= option on the SET statement.  

data final_&vorder;
  if eof then call symputx('nobs',_n_-1);
  set t5 end=eof;
  where &var ne .;
run;

Make sure to put the CALL SYMPUTX() call BEFORE the SET statement. SAS data steps normally stop when they read past the end of the input data. So for an empty input set the statements after the SET statement never run.

 

You could then use the value of &NOBS to control your code.

%if &nobs > 0 %then %do;
* code to process the data ;
%end;
%else %do;
* code to run when input set is empty ;
%end;
kmardinian
Quartz | Level 8

Thank you so much! I appreciate all the help, this definitely help clarify a lot of things. It's working, I ended up using the NOBS option!

 

%if &nobs > 0 %then %do;
* code to process the data ;
%end;
%else %do;
* code to run when input set is empty ;
%end;

 

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!

Register Now

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 8 replies
  • 6859 views
  • 0 likes
  • 5 in conversation