BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Yeti
Calcite | Level 5

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

1 ACCEPTED SOLUTION

Accepted Solutions
Yeti
Calcite | Level 5

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

11 REPLIES 11
SASKiwi
PROC Star

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;

Yeti
Calcite | Level 5

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

jakarman
Barite | Level 11

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

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.

Yeti
Calcite | Level 5

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

Tom
Super User Tom
Super User

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 ;

Yeti
Calcite | Level 5

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

Tom
Super User Tom
Super User

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

Yeti
Calcite | Level 5

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

Yeti
Calcite | Level 5

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.

jakarman
Barite | Level 11

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

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
  • 11 replies
  • 1256 views
  • 6 likes
  • 4 in conversation