BookmarkSubscribeRSS Feed
DanD999
Quartz | Level 8

I'm working with a code module that is called by other code modules. Some of the other code modules that call this common module with have a certain variable set and other code modules won't.

I've tried various code but either I get an error or the code doesn't recognize whether the variable exists or not.

%let choice = yes;
%put cd9 &choice.; 

data have;
input ID Comments:$10. Grade;
cards;
1 abcdefg 2
1 lkjhgff 3
1 poiuytr 1
10 mnbvcxa 1
10 mbdfrte 4
10 qwertyu 2
;
run;

data result;
	set have;
	if %sysfunc(exist(&choice.)) then asgn=catx(' ',comments, &choice.);
	else asgn=catx(' ', comments, ' missing');
run;
data result;
	set have;
	if %symexist(&choice.) then asgn=catx(' ',comments, &choice.);
	else asgn=catx(' ', comments, ' missing');
run;

data result;
	set have;
	if exist(&choice.) then asgn=catx(' ',comments, &choice.);
	else asgn=catx(' ', comments, ' missing');
run;
data result;
	set have;
	if exist(&choice1.) then asgn=catx(' ',comments, &choice1.);
	else asgn=catx(' ', comments, ' missing');
run;

Thanks for any help or guidance you can give. 

18 REPLIES 18
Tom
Super User Tom
Super User

There are a couple of logic issues in your code.  First the EXISTS() function is for datasets, not variables.  Second you cannot test for existence of a variable using datastep logic in the same dataset.  Once you reference a variable in your code the compiler of the data step will see the reference and so the variable will exist in the data step (even if it doesn't exist in the source dataset).

 

In most cases it doesn't matter whether the variable exists or not.   Just make sure to define it before referencing it in your code so that you don't accidentally create the wrong type of variable when it doesn't exist.

 

If you really do need to make different code depending on whether the variable exists or not then you must test for its existence first and then conditionally generate the code using macro logic based on the results of your test.

 

data want;
  set have;
%if %varexist(have,&choice) %then %do;
  * code that references existing variable ;
%end;
%else %do;
  * code that works when variable does not exist ;
%end;
run;
DanD999
Quartz | Level 8

@Tom wrote:

There are a couple of logic issues in your code.  First the EXISTS() function is for datasets, not variables.  Second you cannot test for existence of a variable using datastep logic in the same dataset.  Once you reference a variable in your code the compiler of the data step will see the reference and so the variable will exist in the data step (even if it doesn't exist in the source dataset).

 

In most cases it doesn't matter whether the variable exists or not.   Just make sure to define it before referencing it in your code so that you don't accidentally create the wrong type of variable when it doesn't exist.

 

If you really do need to make different code depending on whether the variable exists or not then you must test for its existence first and then conditionally generate the code using macro logic based on the results of your test.

 

data want;
  set have;
%if %varexist(have,&choice) %then %do;
  * code that references existing variable ;
%end;
%else %do;
  * code that works when variable does not exist ;
%end;
run;

I'm not sure that I understood everything you said. The variable in question is a global variable and not in a dataset. Any number of other code modules will set the variable when they start and then they call a common code module. However, the are some code modules that will not set the variable when they start and therefor I need to know if the variable exists or not. If it doesn't exist then I'll get an error the way the code is now. 

 

So in the common code module I want to know if this variable exists ( has it been set by the calling code module). Would it be possible to test for the variable before the data step and set another variable  to Yes or No depending on whether the variable exists and then use this second variable inside of the data step? 

 

Thanks

Tom
Super User Tom
Super User

There is no such thing as a "global variable".  Perhaps you meant a macro variable (also know as a macro symbol)?

 

To test if a macro variable exists use the macro function %SYMEXIST().

 

If you have an actual macro that you have created and you want to know if there is a global macro variable it is probably easiest to test at the start of the macro execution.

 

For example this code will check if CHOICE has been defined and if not it will create a local macro variable named CHOICE with the value of missing.

%macro mymacro;
%if not %symexist(choice) %then %do;
  %let choice=missing;
%end;
....
%mend ;

For a more detailed example for how to handle your situation you need to explain more about what you are doing. 

For example it might be that you want to check not only whether the macro variable exists but also whether or not it has been given a non-blank value.

DanD999
Quartz | Level 8

@Tom wrote:

There is no such thing as a "global variable".  Perhaps you meant a macro variable (also know as a macro symbol)?

 

To test if a macro variable exists use the macro function %SYMEXIST().

 

If you have an actual macro that you have created and you want to know if there is a global macro variable it is probably easiest to test at the start of the macro execution.

 

For example this code will check if CHOICE has been defined and if not it will create a local macro variable named CHOICE with the value of missing.

%macro mymacro;
%if not %symexist(choice) %then %do;
  %let choice=missing;
%end;
....
%mend ;

For a more detailed example for how to handle your situation you need to explain more about what you are doing. 

For example it might be that you want to check not only whether the macro variable exists but also whether or not it has been given a non-blank value.


Doesn't a statement like 

%global choice; 

create a global variable?

 

I have several code modules that call a code module that is common to all programs. Some of the calling programs set a variable (call it "choice") before running the common code module with an "include" statement.

 

In the common code module there is a very large data step that I'm trying to change as little as possible. There is a statement in the data step that says something like "if "value a" in &choice. then .... else ....

 

When a code module that does not set the variable "choice", calls the common code, there is an error when it gets to the line in the data step that uses the "choice" variable.

 

So I thought if I checked whether the variable exists or not from the calling program, I could do a if-then-else depending on the answer.

 

Thanks

Shmuel
Garnet | Level 18

@DanD999 I hope next code will clarify the usage of %symexist() macro function:

%let x=;
%macro test;
%if %symexist(x) %then %put X; 
%else %put NOx;

%if %symexist(y) %then %put Y; 
%else %put NOy;
%mend;
%test;

the log messages in this example:

 X
 NOy

 

Shmuel
Garnet | Level 18

1)  Using function EXIST(<xxx>) - xxx is a data set name, not a variable name !

2) You assigned:  %let choice = yes; 

     Then in your code &choise is replaced by the string yes.

     Do you mean that the variable to name is yes ?

 

Do you need to check one variable only? is it always the same variable? 

Or maybe you need different variables to check depending on the situation?

 

You can check whether a variable exists in a data set by any of next methods:

1) check existence of the variable in sashelp.vcolumn :

     

%let varname = NAME;
%let exist = 0;
data _null_;
  set sashelp.vcolumnn(where=(libname="ANYLIBRARY" and
       member = "DATA_SET_NAME");
       if _N_then call symput('exist','1');
run;
%put EXIST = &exist;

pay attention = libname and data set name should be in unppercase.

 

2) Next code may be used inside your data step code:

     

data ds_out;
   set any_lib.ds_in;  
        ...
        dsid = open("any_lib.ds_in");
        if dsid > 0 then do;
            exist = varnum(dsid,"var_name");  
            dsid = close(dsid);
        end;
       if exist = 0 then put "VAR_NAME does not exist in lib.ds_in";
       else do;
              ... any code ....
       end;
run;
DanD999
Quartz | Level 8

@Shmuel wrote:

1)  Using function EXIST(<xxx>) - xxx is a data set name, not a variable name !

2) You assigned:  %let choice = yes; 

     Then in your code &choise is replaced by the string yes.

     Do you mean that the variable to name is yes ?

 

This is just sample code. The essence of it is can I test for the existence of a global variable and then do an if-then-else statement based on whether the global variable exists or not?

Do you need to check one variable only? is it always the same variable? 

Or maybe you need different variables to check depending on the situation?

 

You can check whether a variable exists in a data set by any of next methods:

1) check existence of the variable in sashelp.vcolumn :

     

variable is not part of a data set . it's a global variable. also see my explanation in previous post. 

%let varname = NAME;
%let exist = 0;
data _null_;
  set sashelp.vcolumnn(where=(libname="ANYLIBRARY" and
       member = "DATA_SET_NAME");
       if _N_then call symput('exist','1');
run;
%put EXIST = &exist;

pay attention = libname and data set name should be in unppercase.

 

2) Next code may be used inside your data step code:

     

data ds_out;
   set any_lib.ds_in;  
        ...
        dsid = open("any_lib.ds_in");
        if dsid > 0 then do;
            exist = varnum(dsid,"var_name");  
            dsid = close(dsid);
        end;
       if exist = 0 then put "VAR_NAME does not exist in lib.ds_in";
       else do;
              ... any code ....
       end;
run;

Thanks

Shmuel
Garnet | Level 18

Can you add to your shared model a line:

%global choice;   /* force existence of the macro variable without assigning a value */

then you can check whether the global macro variable is assigned a value:

%let chkvar = ABC;  /* this is global by default */
%global none;       /* Force existence of global variable */

%macro chk;
data _NULL_;
   if length("&chkvar") then put "chkvar exists";
   if not length("&none") then put "none do not exist";
run;
%mend;
%chk;
DanD999
Quartz | Level 8

@Shmuel wrote:

Can you add to your shared model a line:

%global choice;   /* force existence of the macro variable without assigning a value */

then you can check whether the global macro variable is assigned a value:

%let chkvar = ABC;  /* this is global by default */
%global none;       /* Force existence of global variable */

%macro chk;
data _NULL_;
   if length("&chkvar") then put "chkvar exists";
   if not length("&none") then put "none do not exist";
run;
%mend;
%chk;

If one of the calling code modules already has created the "choice" variable and populated it will using %Global choice in the common code module program overwrite the variable if it exists?

 

Thanks

Shmuel
Garnet | Level 18

%GLOBAL clause is just a declaration and will not override existing value.

 

By the way, I checked myself and length("&none"), when NONE was not assigned a value,

result in 1 and not 0 as I expected.

 

 

 

 

Tom
Super User Tom
Super User

@Shmuel wrote:

%GLOBAL clause is just a declaration and will not override existing value.

 

By the way, I checked myself and length("&none"), when NONE was not assigned a value,

result in 1 and not 0 as I expected.

 


Blindly adding a %GLOBAL statement inside a macro can cause errors if the macro variable already exists in a currently running macro's local symbol table.  Use the %SYMEXIST() to test for this.

 

In a data step use the LENGTHN() function to return zero when the string only contains blanks.

 

In macro code use the %LENGTH() function to test if a macro variable contains anything (even blanks).

Or use the test described in this classic paper to check if the macro variable non-blank.

https://support.sas.com/resources/papers/proceedings09/022-2009.pdf

DanD999
Quartz | Level 8

@Tom wrote:

@Shmuel wrote:

%GLOBAL clause is just a declaration and will not override existing value.

 

By the way, I checked myself and length("&none"), when NONE was not assigned a value,

result in 1 and not 0 as I expected.

 


Blindly adding a %GLOBAL statement inside a macro can cause errors if the macro variable already exists in a currently running macro's local symbol table.  Use the %SYMEXIST() to test for this.

 

In a data step use the LENGTHN() function to return zero when the string only contains blanks.

 

In macro code use the %LENGTH() function to test if a macro variable contains anything (even blanks).

Or use the test described in this classic paper to check if the macro variable non-blank.

https://support.sas.com/resources/papers/proceedings09/022-2009.pdf


Will lengthn() or %length() work if the variable doesn't exist which is the case now?

Shmuel
Garnet | Level 18

@Tom may I ask, suppose you have a macro program in a macro program:

/* %let choice = xxx; -- either exists as global or does not exits */

%macro main;
   %local choise;
    ...
    %called(....);
   ...
%mend;

%macro called(...arguments ...);
    %global choice;
     %if  %symexist(choice) %then ... ;
%mend;

%main;
      

in such case which macro variable CHOICE shall %symexist() check - the %local or the %global ?

DanD999
Quartz | Level 8

@Shmuel wrote:

@Tom may I ask, suppose you have a macro program in a macro program:

/* %let choice = xxx; -- either exists as global or does not exits */

%macro main;
   %local choise;
    ...
    %called(....);
   ...
%mend;

%macro called(...arguments ...);
    %global choice;
     %if  %symexist(choice) %then ... ;
%mend;

%main;
      

in such case which macro variable CHOICE shall %symexist() check - the %local or the %global ?


I understand your point. Thanks for pointing it out but I don't think it will be an issue in our case. The actual name of the variable is choice_cd9. This code has been running for a long time and is rarely changed so I think that possibility is remote.

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 18 replies
  • 5264 views
  • 0 likes
  • 4 in conversation