Hello all,
I have been given a database in which each 'root' variable has 94 variants, with suffixes running from A to CP (don't ask why - unfortunately it's not something I can change). So for instance, there may exist a 'root' variable called "result", for which in the dataset there exist 94 fields resulta, resultb, ...., resultcp.
Very often I want to drop many of these variables, but not all. I would like to be able to specify a range of variables to drop. The syntax I would like would be something like:
drop = %dropvars(result, 3,5)
which would output
drop = resultc resultd resulte
(I realise that if these variables were contiguous in the dataset, i could specify the range directly. However, I cannot guarantee they will be contiguous, so I need another option..)
Achieving the string "resultc resultd resulte" in a macro variable is relatively easy. For instance, I have a table called suffixes:
i suffix
1 a
2 b
..
94 cp
I can then just do something like:
proc sql;
select suffix
into :suffixlist separated by " "
from suffixes
where i > start and < end;
quit;
However, if this code were part of a macro it gets outputted when I call the macro.
It's therefore not possible to use the macro in code like:
data datadropped;
set database (drop = %dropvars(result, 3,5) );
run;
There are various getarounds to this problem, one of which I have successfully implemented. Basically, this solution involves running the proc sqls first to create macro variables containing the variables to drop, and then using these macro variables in the drop statement. However, it's nowhere near as 'clean' as the code I would like.
Is there any way around this, or is what I want to achieve simply antithetical to the SAS macro system?
Thanks very much for any help,
Robin
Just put the lookup table in a macro variable. It can be in the macro or global.
Since your lookup data resides in a table, it's hard for you to reach that information using an in-line macro.
One quite easy compromise would be to have your SQL executed first, without the where-clause, then have your in-line macro navigate in the resulting macro variable.
Just put the lookup table in a macro variable. It can be in the macro or global.
This is another version that uses the suffix as the arguments not the index.
It is possible to read from a dataset in a macro. You can use %SYSCALL SET() function to link the dataset variables to macro variables so that you can fetch the observations from the table.
data suffixes;
input i suffix $ @@;
cards;
1 a 2 b 3 c 4 d 94 cp
run;
%macro dropvars(prefix,values);
%local i suffix rc did ;
%let did=%sysfunc(open(suffixes(where=(i in (&values))))) ;
%if &did %then %do;
%syscall set(did);
%* Note the single space between end of the do statement and macro variable expansion ;
%do %while (not %sysfunc(fetch(&did))); &prefix.%trim(&suffix) %end;
%let rc=%sysfunc(close(&did));
%end;
%mend dropvars;
%put %dropvars(RESULT,1 3 4);
Thanks all for your input. I've not explored macro functions in as much depth as I should have. Once i've seen how to do it it seems obvious: if you want a sas macro that performs calculations but only outputs the results of those calculations, you need to be using macro functions rather than performing the calculations in base SAS code.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.
Ready to level-up your skills? Choose your own adventure.