Hello,
I have following code that can be run as is:
data test; length Make $13.; declare hash found_keys(); found_keys.definekey('Make','Model'); found_keys.definedone(); do while (not done); set sashelp.cars end=done; rc=found_keys.add(); output; end; stop; run;
I tried to put it into an macro but somehow it won't work. Could anyone tell me why? what should I do in order to resolve the issue?
%macro m_test(key=); data test; length Make $13.; declare hash found_keys(); found_keys.definekey(&key.); found_keys.definedone(); do while (not done); set sashelp.cars end=done; rc=found_keys.add(); output; end; stop; run; %mend;
%m_test(key=%bquote('Make', 'Model'));
If you use %STR() to add the macro quotes in the call it works.
If you add %UNQUOTE() into the macro code to remove any macro quoting before using the value it works.
Personally I would use %QLIST() macro to add the quotes, commas and parentheses.
%macro m_test(keyvars);
data test;
length Make $13.;
declare hash found_keys();
found_keys.definekey%qlist(&keyvars);
found_keys.definedone();
do while (not done);
set sashelp.cars end=done;
rc=found_keys.add();
output;
end;
stop;
run;
%mend;
options mprint;
%m_test(Make Model);
Please very clearly describe what "didn't work" means.
I ran your data step and the macro creating a different data set and the two resulting data sets compare as the same.
Sorry, updated my question. for the case when the key is more than one variable, my setup won't run.
Wrong quoting function, try:
%m_test(key=%str('Make', 'Model'));
Suggestion: if you are trying to duplicate the results of data step code then do not overwrite the data set in the macro. Using the same name for the output data set means you can't compare the sets to see if the results are truly identical.
Considering that your other post https://communities.sas.com/t5/SAS-Programming/how-to-set-up-parameters-in-marco/m-p/937253#M368263 was how to create such a list as your multiple key values without passing it as quoted and comma delimited values I am wondering why that wasn't applied to this code?????
If I setup key=Maker Model, and try to use the answer from my other post, change it to 'Maker', 'Model' and then pass it through this code chunk, it did not work. So I think maybe I need to simply the process: instead of adding a step to make "key=Maker Model" fit, I can set it up as "Key="Marker', 'Model'". But somehow it did not work.😅
If I bind those two together , I can have following codes but it is not working. Not sure how to fix it:
%macro m_test(varlst=); %let key=%str(%')%qsysfunc(tranwrd(&varlst.,%str( ),%str(%', %')))%str(%'); data test; declare hash found_keys(); found_keys.definekey(&key.); found_keys.definedone(); do while (not done); set sashelp.cars end=done; rc=found_keys.add(); output; end; stop; run; %mend; %m_test(varlst=Make Model);
Try
%macro m_test(varlist=); %let key=; %do i = 1 %to %sysfunc(countw(&varlist.)); %let word=%scan(&varlist.,&i.); %if &i=1 %then %let key=%sysfunc(quote(&word.)); %else %let key = &key.,%sysfunc(quote(&word.)); %end; %put Key is: &key.; data test; declare hash found_keys(); found_keys.definekey(&key.); found_keys.definedone(); do while (not done); set sashelp.cars end=done; rc=found_keys.add(); output; end; stop; run; %mend;
Looks like it works with two key variable setup. Then my question is, my earlier code also define key as 'Make', 'Model', why it did not pass to found_keys.definekey() correctly?
If I substitute "key" part with following codes that @yabwon suggested
%let key=%str(%')%qsysfunc(tranwrd(&varlst.,%str( ),%str(%', %')))%str(%'); %put Key is: &key.;
It looks to me the key should be the same as yours, but it won't work. What might be the reason that cause this?
@stataq wrote:
Then my question is, my earlier code also define key as 'Make', 'Model', why it did not pass to found_keys.definekey() correctly?
It's because the %BQUOTE function added invisible macro quoting characters to the parameter in the macro call, but then you did not remove them where necessary:
found_keys.definekey(%unquote(&key.));
@stataq wrote:
what above the case when I set varlst=make model, and used %let key=%str(%')%qsysfunc(tranwrd(&varlst.,%str( ),%str(%', %')))%str(%'); (in one of my reply). Here I did not use %bquote and the value still not pass to found_keys.definkey(). Any idea?
But you did use %QSYSFUNC().
But why add any macro quoting? Just use double quotes instead and you can use %SYSFUNC() instead.
%let key="%sysfunc(tranwrd(&varlist.,%str( ),"%str(,)"))";
Example;
1 %let varlist=a b c ; 2 %let key="%sysfunc(tranwrd(&varlist.,%str( ),"%str(,)"))"; 3 %Put &=varlist &=key ; VARLIST=a b c KEY="a","b","c"
@FreelanceReinh wrote:
@stataq wrote:
Then my question is, my earlier code also define key as 'Make', 'Model', why it did not pass to found_keys.definekey() correctly?It's because the %BQUOTE function added invisible macro quoting characters to the parameter in the macro call, but then you did not remove them where necessary:
found_keys.definekey(%unquote(&key.));
Just to be clear it is not your fault that you did not know to use %UNQUOTE. The macro language should have removed these invisible quoting characters automatically instead of sending them off to cause an error for the DATA step compiler. But there is an old bug that has been there maybe always (?), which means the automatic unquoting sometimes does not work. So if you have introduced macro quoting of any sort, and if the code in shown in your log looks exactly correct but gives an error, it's always good to try adding an explicit %unquote to see if that will resolve the problem.
See for the example in the docs for the %unquote function: https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/mcrolref/p1k3cotqhvgwk0n105gyfe1cqg9m.htm. The docs don't call it a bug, but instead a "problem that can arise" : )
The only difference between your first data step and the data step generated by your call to the macro is the case of the letter M in the name of the key variable you pass to the DEFINEKEY() hash method. And since SAS variable names are case insensitive that should not matter.
What if I want to pass two variables to the definekey()? I tried and failed if I set up key with more than 1 variable.
If you use %STR() to add the macro quotes in the call it works.
If you add %UNQUOTE() into the macro code to remove any macro quoting before using the value it works.
Personally I would use %QLIST() macro to add the quotes, commas and parentheses.
%macro m_test(keyvars);
data test;
length Make $13.;
declare hash found_keys();
found_keys.definekey%qlist(&keyvars);
found_keys.definedone();
do while (not done);
set sashelp.cars end=done;
rc=found_keys.add();
output;
end;
stop;
run;
%mend;
options mprint;
%m_test(Make Model);
149 %let varlist=a b c ; 150 %let key="%sysfunc(prxchange(s/\s+/%str(",")/,-1,&varlist.))"; 151 %Put &=varlist &=key ; VARLIST=a b c KEY="a","b","c"
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.