BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
stataq
Quartz | Level 8

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'));
1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

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);

 

View solution in original post

15 REPLIES 15
ballardw
Super User

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.

stataq
Quartz | Level 8

Sorry, updated my question. for the case when the key is more than one variable, my setup won't run.

ballardw
Super User

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?????

stataq
Quartz | Level 8

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);
ballardw
Super User

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;

 

 

 

stataq
Quartz | Level 8

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?

FreelanceReinh
Jade | Level 19

@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
Quartz | Level 8
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?
Tom
Super User Tom
Super User

@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"

Quentin
Super User

@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 Boston Area SAS Users Group is hosting free webinars!
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.
Tom
Super User Tom
Super User

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.

stataq
Quartz | Level 8

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.

Tom
Super User Tom
Super User

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);

 

Ksharp
Super User
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: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 15 replies
  • 1840 views
  • 14 likes
  • 7 in conversation