DATA Step, Macro, Functions and more

Assign a value fetched from a macro subroutine to a dataset variable

Accepted Solution Solved
Reply
Contributor
Posts: 32
Accepted Solution

Assign a value fetched from a macro subroutine to a dataset variable

Greetings,

I am trying to derive a value based on an existing column in a dataset.  I did countless tests based on the examples found in the internet but to no avail.

Can somebody help me please?

%macro test1(x);

    %if &x=1 %then %let i = "One";

             %else %let i = "Not One";

    &i;

%mend;

data test;

x = 1;

run;

data test1;

set test;

b = %test1(x);

run;

I get an unexpected value when I run the above program.

Test1:

        x    |     b

    ----------|----------

       1     |    Not One

What I am trying to achieve is:

Test1:

        x    |     b

    ----------|----------

       1     |    One

It seems like I am totally misunderstanding how calling macro to derive a value.

I appreciate your help.

Thank you very much.

Naresh


Accepted Solutions
Solution
‎02-28-2015 01:26 PM
Contributor
Posts: 32

Re: Assign a value fetched from a macro subroutine to a dataset variable

Thank you guys.  Your advice were very helpful.  Yes, I was treating the macro as a function/subroutine.  That is not the case in SAS.  I am very clear now. Smiley Happy

After a long night sleep, and rethinking my strategy, I was able to achieve what I was looking for.

Here is my code that works like a charm. Smiley Happy

data _null_;

  date = '01mar2015'd;

  Call Symput('this_mnth' , month(date));

  Call Symput('this_factor',month(date)-1);

run;

%put &this_mnth;

%put &this_factor;

DATA test;

   INPUT mm $;

   DATALINES;

12

11

10

09

08

07

06

05

04

03

02

01

;

run;

%macro mm1(mm);

         if (put(&mm,$2.)+&this_factor) > 12 then do; mm1 = put((input(&mm,$2.)-12 + &this_factor), z2.); end;

                                            else do; mm1 = put(input(&mm,$2.)+&this_factor,z2.); end;

%mend;

data test1;

set test;

length mm1 $2.;

%mm1(mm);

run;

Result:

mm    |    mm1

12    |    02

11    |    01

10    |    12

09    |    11

08    |    10

07    |    09

06    |    08

05    |    07

04    |    06

03    |    05

02    |    04

01    |    03

Thank you very much.

Have a great weekend.

Naresh

View solution in original post


All Replies
Super User
Posts: 3,112

Re: Assign a value fetched from a macro subroutine to a dataset variable

By putting x as the value to pass to your macro test1, this is just the text x, not the value of the SAS variable x. Then &x in your macro has the value x hence the macro returns 'Not 1'.

Run your code with the statement options symbolgen; and you will see what is happening more clearly.

Trying to assign a value to a SAS variable from another SAS variable is best done without macro code at all for example:

proc format;

  value testone

  1 = 'One'

  other = 'Not One'

;

run;

data test1;

  set test;

  b = put(x, testone.);

  put _all_;

run;

Contributor
Posts: 32

Re: Assign a value fetched from a macro subroutine to a dataset variable

Thank you Kiwi for your help.  Your user defined format solution is very clever.  I will remember that.

Now, I am even more confused as I can see the values getting passed in this code:

%macro mm1(mm);

          %let date = '01feb2015'd;

          %let this_mnth=%sysfunc(month(&date));

        %let in_mm = %sysfunc(inputc(&mm,$2.));

        %if &this_mnth = 1 %then %do; %let i = &in_mm ; %end;

                      %else %do; %if &mm = '12' %then %do; %let mm2 = 0; %end;

                                              %else %do; %let mm2= &in_mm; %end;

                                 %let i = &mm2+ 1;

                            %end;

    put(&i,z2.);

%mend;

DATA test;

   INPUT mm $;

   DATALINES;

12

11

10

09

08

07

06

05

04

03

02

01

;

run;

data test1;

set test;

length mm1 $2.;

mm1 = %mm1(mm);

run;

I just can not get the mm1=1 for mm=12, instead I get mm1=13.

I am fairly new to SAS but I do have very strong programing experience.

Thank you again for your help.

Cheers,

Naresh

Valued Guide
Posts: 3,208

Re: Assign a value fetched from a macro subroutine to a dataset variable

Naresh, as you are having very strong programming experience do the translation of words and meanings form other languages to SAS datastep/macro.  A word can have different meanings Homonym - Wikipedia, the free encyclopedia and different words can have the same meaning Synonym - Wikipedia, the free encyclopedia  that is for making thing more difficult (IT nerd job protection).  It is about getting the semantics right.

A SAS macro is just a string editor / preprocessor not a function. Within Excel however a macro is the recoding of actions being executed.

http://en.wikipedia.org/wiki/Macro_(computer_science)  this is the difference between procedural and syntactic. See SAS as being based on PL/1.

---->-- ja karman --<-----
Super User
Super User
Posts: 6,502

Re: Assign a value fetched from a macro subroutine to a dataset variable

First of all a macro is not a subroutine.  Macro language is a code generating tool.  Once the macro processor has finished expanding all of the macro references the generated code is then passed to the SAS process to run the same as it would have if you had just typed the code into the program.

Let's simplify your macro and change the parameter name to avoid confusion between the parameter name (a local macro variable) and the value you are passing the macro.

%macro test1(value); %if &value=1 %then "One"; %else "Not One"; %mend test1 ;

Now your example data step code becomes:

data test1;

  set test;

  b = %test1(value=X) ;

run;

First SAS will process the macro call. So substituting the X for the reference to &value your %IF condition is now testing if X=1 which is obviously false since the letter X is not the same as the digit 1.  And the SAS code that the macro generates and passes to the SAS process to use as part of your DATA step is "Not One";

So your data step code becomes :

data test1;

  set test;

  b = "Not One";

run;


Notice that the value assigned to the variable B has nothing to do with the value of any variable your SAS dataset since it was determined BEFORE the data step even starts to run.

Solution
‎02-28-2015 01:26 PM
Contributor
Posts: 32

Re: Assign a value fetched from a macro subroutine to a dataset variable

Thank you guys.  Your advice were very helpful.  Yes, I was treating the macro as a function/subroutine.  That is not the case in SAS.  I am very clear now. Smiley Happy

After a long night sleep, and rethinking my strategy, I was able to achieve what I was looking for.

Here is my code that works like a charm. Smiley Happy

data _null_;

  date = '01mar2015'd;

  Call Symput('this_mnth' , month(date));

  Call Symput('this_factor',month(date)-1);

run;

%put &this_mnth;

%put &this_factor;

DATA test;

   INPUT mm $;

   DATALINES;

12

11

10

09

08

07

06

05

04

03

02

01

;

run;

%macro mm1(mm);

         if (put(&mm,$2.)+&this_factor) > 12 then do; mm1 = put((input(&mm,$2.)-12 + &this_factor), z2.); end;

                                            else do; mm1 = put(input(&mm,$2.)+&this_factor,z2.); end;

%mend;

data test1;

set test;

length mm1 $2.;

%mm1(mm);

run;

Result:

mm    |    mm1

12    |    02

11    |    01

10    |    12

09    |    11

08    |    10

07    |    09

06    |    08

05    |    07

04    |    06

03    |    05

02    |    04

01    |    03

Thank you very much.

Have a great weekend.

Naresh

Super User
Super User
Posts: 6,502

Re: Assign a value fetched from a macro subroutine to a dataset variable

You still have some very confused code there.

Why would you want to apply the $2 format to a character variable MM?  put(MM,$2.).  How did you think this was going to transform the data?

Why would you add a number (&THIS_FACTOR which evaluated to 2) to the output of a character function (PUT()) ?

Why are you storing months as character strings to begin with?  Why not just store them as numbers and attach the Z2. format to them it you want them to print with leading zeros?

Also why such a complicated algorithm to implement modulo function?

  mm1=mod((mm-1) +&this_factor ,12) +1 ;

Contributor
Posts: 32

Re: Assign a value fetched from a macro subroutine to a dataset variable

Yes Tom, you are correct.  The first 'put' should be input as the rest of the mm conversions. Smiley Happy

The 'mm' variable is already a string type in the existing dataset.  I am just refining the existing code.

The existing code (coded by business not IT)  is as follows and it requires a manual intervention every month.  I am trying to automate this piece. mm1 values stack/rotate down each month.  Don't ask me why. :smileygrin:

if       mm = '12' then do; ----------------; mm1 = '02';end;   /*mar*/

else if mm = '11' then do; ----------------; mm1 = '01';end;  

else if mm = '10' then do; ------r---------; mm1 = '12';end;

else if mm = '09' then do; ------e---------; mm1 = '11';end;

else if mm = '08' then do; ------m---------; mm1 = '10';end;

else if mm = '07' then do; ------o---------; mm1 = '09';end;

else if mm = '06' then do; ------v---------; mm1 = '08';end;

else if mm = '05' then do; ------e---------; mm1 = '07';end;

else if mm = '04' then do; ------d---------; mm1 = '06';end;

else if mm = '03' then do; ----------------; mm1 = '05';end;

else if mm = '02' then do; ----------------; mm1 = '04';end;

else if mm = '01' then do; ----------------; mm1 = '03';end;

The piece of code I posted was just a test script.

Thank you again for your help.

Cheers,

Naresh

Super User
Super User
Posts: 6,502

Re: Assign a value fetched from a macro subroutine to a dataset variable

It is probably even easier to leave the values as dates instead of parsing them into separate month,day,year variable.

new_date = intnx('month',old_date + &this_factor,'s') ;

Contributor
Posts: 32

Re: Assign a value fetched from a macro subroutine to a dataset variable

Thanks Tom.  I would have left the dates as dates as you have mentioned above.

I am only helping them automate their monthly manual process that stacks down the months as mentioned above.  The job ran yesterday without any problem.  Next month, there will be no manual intervention.  Ticket closed. Smiley Happy

Cheers.

Naresh

Contributor
Posts: 32

Re: Assign a value fetched from a macro subroutine to a dataset variable

Tom wrote:

Also why such a complicated algorithm to implement modulo function?

  mm1=mod((mm-1) +&this_factor ,12) +1 ;

Excellent logic.  This is too good.

Thank you again.

Valued Guide
Posts: 3,208

Re: Assign a value fetched from a macro subroutine to a dataset variable

Naresh, Non ICT people are as stubborn to their home-invented solutions as ICT people.

You described a moving window the left comment 02 mar is indication for a 3 month period.

Good ICT people are knowing what release management (DTAP) and version management is about. Some consequences are:

- eliminating all physical names from code, solve that in other way.

  hardcoding of users and password into code is even often done.  Copied from samples. No discussion I hope that is very bad.

- For moving windows there should be some standard how to work with those and supporting a simulated today function "reference date".

  Yep, ost people are coding the systemdate into business  logic. That is ok for logging not for business processes,

  Do you want to test/verify dataflow (acceptance testing) the results should be predictable. With fixed testsets you should have a fixed "" reference date".

  Do you want to run jobs later (recover from some hold-up) or earlier (planned holiday-s) it can necessary to have that reference-date not of the one today.

  The surprises caused by running a next day in the weekend (being next month/year) are mostly hilarious but it is the same, to be avoided.

You did state to having good programming skills.
How are the ICT skills with a vision to operations, business continuity, easy maintenance of code/processes?        

---->-- ja karman --<-----
☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 11 replies
  • 385 views
  • 6 likes
  • 4 in conversation