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

Hi there, thank you so much for the feedback! The delete_these dataset captures exactly what I want (to identify everything except var=3).

 

However, something is going wrong in the call execute function (see attached log). I tried to troubleshoot error 180-322 but wasn't able to find a fix for this specific situation.

 

Suggestions?

Astounding
PROC Star

For starters, let's try inserting a STOP statement in the DATA _NULL_ step:

 

   data _null_;
      call execute ('%symdel ');
      do until (done);
         set delete_these end=done;
         call execute(name);
      end;
      call execute (';') ;
      STOP;
   run; 

That's definitely needed, so let's see if that takes care of all the problems.

LFern
Obsidian | Level 7

Even with the stop, I'm getting the same 180-322 error as before:

 

NOTE: CALL EXECUTE generated line.

2 + VAR1

NOTE: Line generated by the CALL EXECUTE routine.

2 + VAR1

----

180

ERROR 180-322: Statement is not valid or it is used out of proper order.

LFern
Obsidian | Level 7

I think I got something to work! I took the first part of your macro (where you create "delete_these") but used a different execute function that I found online:

 

----------------------------

%let VAR1 = 1;

%let VAR2 = 2;

%let VAR3 = 3;

%macro delvars(except=);

 

proc sort data=sashelp.vmacro nodupkey out=delete_these;

by name;

where scope='GLOBAL' and upcase(name) not in

( %do k = 1 %to %sysfunc(countw(&except) ) ;

"%upcase(%scan(&except, &k))"

);%end;

run;

 

 

data _null_;

set delete_these;

if scope="GLOBAL" then call execute ('%symdel ' || trim(left(name))||';');

run;

%mend; %delvars(except=var3);

 

--------------------------

 

It worked for me as far as I can tell. %put _global_ now only returns var3.

 

Do you see anything obviously problematic?

Tom
Super User Tom
Super User

SAS did not like getting the %SYMDEL statement sent to it by CALL EXECUTE in multiple pieces.  The first %SYMDEL code was interpreted by the macro processor and put nothing onto the stack of commands to run after the data step.

So it ended up thinking you are trying to run a command like:

VAR1 VAR2 ;

By sending a complete %SYMDEL statement in each CALL EXECUTE string you avoid that problem.  

call execute(catx(' ','%symdel',name,';'));

You could also have fixed this by wrapping the original %SYMDEL code inside of %NRSTR() so that the %SYMDEL statement would be pushed onto the stack to execute after the data step.

1780  %put &=var1 &=var2 &=var3; ;
VAR1=x VAR2=x VAR3=x
1781  data _null_;
1782    if _n_=1 then call execute('%nrstr(%symdel) ');
1783    if eof then call execute(';');
1784    set test end=eof;
1785    call execute(name);
1786  run;

NOTE: There were 3 observations read from the data set WORK.TEST.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


NOTE: CALL EXECUTE generated line.
1    + %symdel
2    + var1
3    + var2
4    + var3
5    + ;
1787  %put &=var1 &=var2 &=var3; ;
WARNING: Apparent symbolic reference VAR1 not resolved.
WARNING: Apparent symbolic reference VAR2 not resolved.
WARNING: Apparent symbolic reference VAR3 not resolved.
var1 var2 var3
Astounding
PROC Star

Well done!

 

These issues aren't problematic, but are things I would change.

 

Now:

if scope="GLOBAL" then call execute ('%symdel ' || trim(left(name))||';');

Suggested changes:

call execute ('%symdel ' || name || ';' );

The previous step already subset based on SCOPE, so no need to do it again here.  And NAME is limited to 32 characters.  I would remove the functions to improve the readability of the code.  A few extra blanks won't hurt anything.

Tom
Super User Tom
Super User

Note sure why you need to worry about deleting macro variables (symbols).  They aren't doing anybody any harm.

But your macro can be a lot simpler and more flexible.

Here is version that allows listing names to include, exclude or a prefix.

%macro delete_most(include,exclude,prefix);
%local list;
proc sql noprint;
  select name into :list separated by ' '
  from dictionary.macros
  where offset=0 and scope='GLOBAL'
%if %length(&prefix) %then 
    and name like %upcase(%bquote('&prefix%'))
;
%if %length(&include) %then 
    and findw("&include",name,' ','sit')
;
%if %length(&exclude) %then
    and not findw("&exclude",name,' ','sit')
;
  ;
quit;
%if &sqlobs %then %do;
  %symdel &list;
%end;
%mend delete_most; 

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!

Mastering the WHERE Clause in PROC SQL

SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 21 replies
  • 3162 views
  • 1 like
  • 6 in conversation