- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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'));
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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);
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Sorry, updated my question. for the case when the key is more than one variable, my setup won't run.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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?????
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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);
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
@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.));
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
@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"
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
@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" : )
Next webinar will be in January 2025. Until then, check out our archives: https://www.basug.org/videos. And be sure to subscribe to our our email list.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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);
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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"