function in a macro

Reply
Contributor fre
Contributor
Posts: 35

function in a macro

Hi,

i have a little problem.

In a macro, i would like to call a function and return a value.

The problem is that the return value (catlog) always returns '20', whatever the value of the variable AANTAL_WONINGEN is.

AANTAL_WONINGEN is a numeric variable.  Whether it has value 1, 12 or 50, it always returns '20'.

I can't see why this code doesn't work. Maybe anyone else can see the problem?

here is the code:

%macro start_BG_NIEUW_1_compute(input_table=, output_table=);

     data temp1;

     set &input_table;

     %let n=AANTAL_WONINGEN;

     %tab_cat_log(aantal=&n);

     CD_CAT_LOGEMENT = &catlog;

     run;

%mend start_BG_NIEUW_1_compute;

%macro tab_cat_log(aantal=);

%global catlog;

     %if &aantal = 1 %then %let catlog = '02';

     %else %if &aantal = 2 %then %let catlog = '03';

     %else %if &aantal = 3 %then %let catlog = '04';

     %else %if &aantal = 4 %then %let catlog = '05';

     %else %if &aantal = 5 %then %let catlog = '06';

     %else %if &aantal = 6 %then %let catlog = '07';

     %else %if &aantal = 7 %then %let catlog = '08';

     %else %if &aantal = 8 %then %let catlog = '09';

     %else %if &aantal = 9 %then %let catlog = '10';

     %else %if &aantal < 15 %then %let catlog = '11';

     %else %if &aantal < 20 %then %let catlog = '12';

     %else %if &aantal < 25 %then %let catlog = '13';

     %else %if &aantal < 30 %then %let catlog = '14';

     %else %if &aantal < 40 %then %let catlog = '15';

     %else %if &aantal < 50 %then %let catlog = '16';

     %else %if &aantal < 60 %then %let catlog = '17';

     %else %if &aantal < 80 %then %let catlog = '18';

     %else %if &aantal < 100 %then %let catlog = '19';

     %else %let catlog = '20';

%mend tab_cat_log;

Super User
Posts: 5,426

Re: function in a macro

You are mixing programming techniques which is not working as you expect.

Am I correct to assume that you want to hold a mapping logic (aantal_xxx -> cat_log_yyy) separate in a sort of isolated function?

There are more elegant ways to  do this, on is to use SAS formats:

%macro start_BG_NIEUW_1_compute(input_table=, output_table=);

     data &output_table;

     set &input_table;

     CD_CAT_LOGEMENT = put(AANTAL_WONINGEN, aant2catlogFmt.);

     run;

%mend start_BG_NIEUW_1_compute;

And I took the liberty to change the step to use your input parameter output_table....

Data never sleeps
Contributor fre
Contributor
Posts: 35

Re: function in a macro

i do not understand very well what you mean with aant2catlogFmt.

What does it refer to?  I thought I need to make a reference in my datastep to the second macro (%macro tab_cat_log).

Contributor fre
Contributor
Posts: 35

Re: function in a macro

when I replace

  %let n=AANTAL_WONINGEN;

by

  %let n=1; (or any other number)

the macro works well and the right category returns.

How can I assign to the macrovariable n the value from the variable AANTAL_WONINGEN in the datastep?

I tried symput, but it didn't work either.

Super Contributor
Posts: 334

Re: function in a macro

The way you are using %let SAS is setting n to the value "AANTAL_WONINGEN" and not to the variable value of AANTAL_WONINGEN in the dataset so that is why it is returning the 'else' value all the time. If you replace the %let line with "call symputx('n',AANTAL_WONINGEN);" I think you get closer to what you want.

is right using the format method would probably lead to better results.  Frankly since you already had all the "if ... then" statements typed into the second macro, I dont know why you just didnt use standard datastep "if ...then" to set the values. I dont think you need any macros to accomplish what you have described.

Hope this helps!

EJ

Contributor fre
Contributor
Posts: 35

Re: function in a macro

The reason why I put it in a macro is because it is a part that will be referenced to from other macros multiple times.

i've adapted the first macro as follow.  It didn't change the output.  It keeps returning value 20. Can't find what's going on ...

%macro start_BG_NIEUW_1_compute(input_table=, output_table=);

     data temp1;

     set &input_table;

          call symputx('n',AANTAL_WONINGEN);

          %tab_cat_log(aantal=&n);

          CD_CAT_LOGEMENT = &catlog;

     run;

     /* some other code ....*/

%mend start_BG_NIEUW_1_compute;

didn't change the second macro.

Super Contributor
Posts: 334

Re: function in a macro

After your message came across it hit me that call symput would not work either because the macro variable would not be available until after the data step concludes.

So the best way to go would be to use a format, but if you want to use a macro I would do the following:

%macro tab_cat_log(aantal,othervar);

length &othervar $ 2;

     if &aantal = 1 then &othervar = '02';

          else if &aantal = 2 then &othervar = '03';

               else if &aantal = 3 then &othervar = '04';    

                    else if &aantal = 4 then &othervar = '05';

                         else if &aantal = 5 then &othervar = '06';

         else if &aantal = 6 then &othervar = '07';

     else if &aantal = 7 then &othervar = '08';

     else if &aantal = 8 then &othervar = '09';

     else if &aantal = 9 then &othervar = '10';

     else if &aantal < 15 then &othervar = '11';

     else if &aantal < 20 then &othervar = '12';

     else if &aantal < 25 then &othervar = '13';

     else if &aantal < 30 then &othervar = '14';

     else if &aantal < 40 then &othervar = '15';

     else if &aantal < 50 then &othervar = '16';

     else if &aantal < 60 then &othervar = '17';

     else if &aantal < 80 then &othervar = '18';

     else if &aantal < 100 then &othervar = '19';

     else &othervar = '20';

%mend tab_cat_log;

%macro start_BG_NIEUW_1_compute(input_table=, output_table=);

     data temp1;

     set &input_table;

     %tab_cat_log(AANTAL_WONINGEN,cd_cat_logement);

      run;

%mend start_BG_NIEUW_1_compute;

Hope this helps!

EJ

Super Contributor
Posts: 334

Re: function in a macro

just remember that < 20 would include 15 and so forth by the natural of the way you setup the logic.

EJ

Respected Advisor
Posts: 3,156

Re: function in a macro

call symput + call execute:

data _null_;

  set sashelp.class;

  call symputx('age',age);

  call execute('%put age=&age');

run;

Super Contributor
Posts: 334

Re: function in a macro

Thanks I knew I was forgetting something!

So I think if you put:

call execute('%tab_cat_log(AANTAL_WONINGEN,cd_cat_logement');

instead of just the macro call you might have better results.

EJ

Respected Advisor
Posts: 3,156

Re: function in a macro

The reason it keeps returning 20 because you always input 'AANTAL_WONINGEN" as the macro variable value. You can't pass on data step variable value to macro variable like this. The more appropriate ways may involve using

1. call symput() to pass on values, then

2. Call execute to invoke macros.

When debugging, it helps if you turn on Symbolgen, Mprint and Mlogic options.

Haikuo

Super User
Posts: 5,426

Re: function in a macro

It refers to a SAS format that you need to create, based in the interval you have in your %if logic.

This will lead to a centric approach to manage a business rule, and possible data driven.

Base SAS(R) 9.4 Procedures Guide

Data never sleeps
Super User
Super User
Posts: 7,039

Re: function in a macro

So your problem is a confusion of when macro logic executes relative to when the generated SAS code runs.

Most likely you would get better results by creating a format and using that, but you can get results from this type of macro by using the RESOLVE() function in a data step.  With the current definition of the macro function your data step could look like this.

data temp1;

  set &input_table;

   length CD_CAT_LAGEMENT $4 ;

  CD_CAT_LOGEMENT = resolve(cats('%tab_cat_log(aantal=',AANTAL_WONINGEN,')');

  CD_CAT_LOGEMENT = symget('catlog');

run;


But do you really want CD_CAT_LAGEMENT to be a character variable with single quotes embedded in them? Now if you turned your macro into a true function style macro that returns the result as the value of the macro instead of setting it into a macro variable it would work better.

%macro tab_cat_log(aantal);

%local catlog;

     %if &aantal = 1 %then %let catlog = 02;

     %else %if &aantal = 2 %then %let catlog = 03;

     %else %if &aantal = 3 %then %let catlog = 04;

     %else %if &aantal = 4 %then %let catlog = 05;

     %else %if &aantal = 5 %then %let catlog = 06;

     %else %if &aantal = 6 %then %let catlog = 07;

     %else %if &aantal = 7 %then %let catlog = 08;

     %else %if &aantal = 8 %then %let catlog = 09;

     %else %if &aantal = 9 %then %let catlog = 10;

     %else %if &aantal < 15 %then %let catlog = 11;

     %else %if &aantal < 20 %then %let catlog = 12;

     %else %if &aantal < 25 %then %let catlog = 13;

     %else %if &aantal < 30 %then %let catlog = 14;

     %else %if &aantal < 40 %then %let catlog = 15;

     %else %if &aantal < 50 %then %let catlog = 16;

     %else %if &aantal < 60 %then %let catlog = 17;

     %else %if &aantal < 80 %then %let catlog = 18;

     %else %if &aantal < 100 %then %let catlog = 19;

     %else %let catlog = 20;

&catlog.

%mend tab_cat_log;

%macro start_BG_NIEUW_1_compute(input_table=, output_table=);

data &output_table;

  set &input_table;

  length CD_CAT_LAGEMENT $2 ;

  CD_CAT_LOGEMENT = resolve(cats('%tab_cat_log(',AANTAL_WONINGEN,')');

run;

%mend start_BG_NIEUW_1_compute;

Ask a Question
Discussion stats
  • 12 replies
  • 397 views
  • 0 likes
  • 5 in conversation