BookmarkSubscribeRSS Feed
fre
Quartz | Level 8 fre
Quartz | Level 8

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;

12 REPLIES 12
LinusH
Tourmaline | Level 20

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
fre
Quartz | Level 8 fre
Quartz | Level 8

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

fre
Quartz | Level 8 fre
Quartz | Level 8

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.

esjackso
Quartz | Level 8

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

fre
Quartz | Level 8 fre
Quartz | Level 8

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.

esjackso
Quartz | Level 8

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

esjackso
Quartz | Level 8

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

EJ

Haikuo
Onyx | Level 15

call symput + call execute:

data _null_;

  set sashelp.class;

  call symputx('age',age);

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

run;

esjackso
Quartz | Level 8

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

Haikuo
Onyx | Level 15

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

LinusH
Tourmaline | Level 20

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
Tom
Super User Tom
Super User

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;

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 12 replies
  • 933 views
  • 0 likes
  • 5 in conversation