DATA Step, Macro, Functions and more

Create, increment and use a macro variable in the same data step?

Accepted Solution Solved
Reply
Contributor
Posts: 72
Accepted Solution

Create, increment and use a macro variable in the same data step?

Can you create a macro variable, increment it (it's numeric) and use it in the same DATA step? If so, how?

A call SYMPUTwill not work, Slaughter and Delwiche (2004) elaborates, "Be careful. You cannot create a macro variable with CALL SYMPUT and use it in the same DATA step. Here’s why. When you submit macro code, it is resolved by the macro processor, and then compiled and executed. Not until the final stage—execution—does SAS see your data. CALL SYMPUT takes a data value from the execution phase, and passes it back to the macro processor for use in a later step. That’s why you must put CALL SYMPUT in one DATA step, but not use it until a later

step" (p. 11)

Slaughter, S.J., Delwiche, L. D. (2004). SAS Macro Programming for Beginners. Retrieved from http://www2.sas.com/proceedings/sugi29/243-29.pdf.


Accepted Solutions
Solution
‎06-29-2012 04:13 PM
Respected Advisor
Posts: 3,777

Re: Create, increment and use a macro variable in the same data step?

You can do it.  It has no practical use that I can think of.

81   data _null_;

82      a = 100;

83      call symputX('a',a);

84      call execute('%put NOTE: A=&a;');

85      do i = 1 to 10;

86         call execute('%put NOTE: Before: A=&a;');

87         a = symgetN('a') + 1;

88         call symputX('a',a);

89         call execute('%put NOTE- After : A=&a;');

90         end;

91      run;

NOTE: A=100

NOTE: Before: A=100

      After : A=101

NOTE: Before: A=101

      After : A=102

NOTE: Before: A=102

      After : A=103

NOTE: Before: A=103

      After : A=104

NOTE: Before: A=104

      After : A=105

NOTE: Before: A=105

      After : A=106

NOTE: Before: A=106

      After : A=107

NOTE: Before: A=107

      After : A=108

NOTE: Before: A=108

      After : A=109

NOTE: Before: A=109

      After : A=110

NOTE: DATA statement used (Total process time):

      real time           0.03 seconds

      cpu time            0.03 seconds

NOTE: CALL EXECUTE routine executed successfully, but no SAS statements were generated

View solution in original post


All Replies
Solution
‎06-29-2012 04:13 PM
Respected Advisor
Posts: 3,777

Re: Create, increment and use a macro variable in the same data step?

You can do it.  It has no practical use that I can think of.

81   data _null_;

82      a = 100;

83      call symputX('a',a);

84      call execute('%put NOTE: A=&a;');

85      do i = 1 to 10;

86         call execute('%put NOTE: Before: A=&a;');

87         a = symgetN('a') + 1;

88         call symputX('a',a);

89         call execute('%put NOTE- After : A=&a;');

90         end;

91      run;

NOTE: A=100

NOTE: Before: A=100

      After : A=101

NOTE: Before: A=101

      After : A=102

NOTE: Before: A=102

      After : A=103

NOTE: Before: A=103

      After : A=104

NOTE: Before: A=104

      After : A=105

NOTE: Before: A=105

      After : A=106

NOTE: Before: A=106

      After : A=107

NOTE: Before: A=107

      After : A=108

NOTE: Before: A=108

      After : A=109

NOTE: Before: A=109

      After : A=110

NOTE: DATA statement used (Total process time):

      real time           0.03 seconds

      cpu time            0.03 seconds

NOTE: CALL EXECUTE routine executed successfully, but no SAS statements were generated

Contributor
Posts: 72

Re: Create, increment and use a macro variable in the same data step?

Your code works like a charm...and for the practical part - my last and final step of what I'm trying to accomplish based on your excellent code:

Your code works, unfortunately mine chokes on me adding the final part...

81   data output_ds;

        set input_ds

82      a = 100;

83      call symputX('a',a);

84      call execute('%put NOTE: A=&a;');

85      do i = 1 to 10;

86         call execute('%put NOTE: Before: A=&a;');

87         a = symgetN('a') + 1;

88         call symputX('a',a);

89         call execute('%put NOTE- After : A=&a;');

          /* I want to clear fields in a column that end in '&a' */

          column1_&a = .;

          column2_&a = .;

          column3_&a = .;

90         end;

91      run;

Trusted Advisor
Posts: 1,300

Re: Create, increment and use a macro variable in the same data step?

The reason DN's example works is because symgetn gets resolves the variable during run time.  The single quoted string inside call execute also resolves at run time.  You example: &a in plain text will resolve at compile time.

data _null_;

a = 100;

call symputX('a',a);

call execute('%put NOTE: A=&a;');

do i = 1 to 10;

    call execute('%put NOTE: Before: A=&a;');

    a = symgetN('a') + 1;

   call symputX('a',a);

   call execute('%put NOTE- After : A=&a;');

   call execute("%put NOTE- Nope  : A=&a;");

   call execute('%nrstr(%put NOTE: After After... : A=&aSmiley Wink');

   end;

run;

You would probably be better off approaching the problem with arrays, hopefully you can find the following directional:

data have;

length a 3;

array column_[100] 3 (100*1);

do _n_=1 to 100;

  a=ceil(100*ranuni(1));

  output;

end;

run;

data want;

length a 3;

array column_[100];

set have;

column_=.;

run;

Respected Advisor
Posts: 3,777

Re: Create, increment and use a macro variable in the same data step?

I thought your question was rhetorical.  (or whatever the right word is).

I'm pretty sure can do what you want without involving macro variables.  If you could show a bit of your data.  The have/want scenario that would be good.

Contributor
Posts: 72

Re: Create, increment and use a macro variable in the same data step?

Thank you everyone - I can see that I'm in a room full of macro experts and your help is appreciated.

Ok, per your suggestion - here is the scenario:

byear  eyear  f1_2009 f2_2009 f1_2010 f2_2010 f2_2011 f1_2011 f1_2012 f2_2012

2010   2012   1       .       .       1       1       .       1       .

.      .      .       1       1       1       1       .       .       1     

2009   2011   1       1       1       .       1       .       .       1

.      .      .       .       1       .       1       .       1       1     

.      .      .       1       1       .       1       1       1       .

2009   2009   1       1       1       1       .       1       .       .

Basically, I want to zero out the fields that fall between the begin year (byear) and the end year (eyear). For example, on line three, I would like to set fn_2009 = ., fn_2010 = ., fn_2011 = . since they all fall within years 2009-2011.

Here’s my basic premise…

data out_ds;

   set in_ds;

   if byear~=. then

      do;

         do while (byear <= eyear);

            call symputx('year', byear);

            call execute('%put &year;');

            f1_&year=.;

            f2_&year=.;

            ...

            byear=byear+1;

         end;

      end;

run;  

Ever had the feeling that you're over thinking something - I'm there currently ;o)

Super Contributor
Posts: 376

Re: Create, increment and use a macro variable in the same data step?

Does this give you what you want?

HTH,

Scott

data have;

  input byear  eyear  f1_2009 f2_2009 f1_2010 f2_2010 f2_2011 f1_2011 f1_2012 f2_2012;

  datalines;

2010   2012 1       .       . 1       1       . 1       .

.      . .       1       1 1       1       . .       1    

2009   2011 1       1       1 .       1       . .       1

.      . .       .       1 .       1       . 1       1    

.      . .       1       1 .       1       1 1       .

2009   2009 1       1       1 1       .       1 .       .

;

run;

data want;

  set have;

  array vars{*} f1_2009 -- f2_2012;

  do i=1 to dim(vars);

    vname=vname(vars{i});

    vyear=input(scan(vname,2,"_"),best.);

       if byear <= vyear <= eyear then call missing(vars{i});

  end;

run;


If any of this is unclear, hit the doc on the array statement (and examples), plus the vname, input, and scan functions, plus the call missing routine (you could also just assign vars{i}=. if you prefer).

Respected Advisor
Posts: 3,124

Re: Create, increment and use a macro variable in the same data step?

Maybe I have oversimplied your problem, but it does look like a simple array() problem:

data have;

input byear  eyear  f1_2009 f2_2009 f1_2010 f2_2010 f2_2011 f1_2011 f1_2012 f2_2012;

cards;

2010   2012   1       .       .       1       1       .       1       .

.      .      .       1       1       1       1       .       .       1    

2009   2011   1       1       1       .       1       .       .       1

.      .      .       .       1       .       1       .       1       1    

.      .      .       1       1       .       1       1       1       .

2009   2009   1       1       1       1       .       1       .       .

;

data want;

set have;

array f f1_2009--f2_2012;

do over f;

f=ifn(byear <= scan(vname(f),2,'_') <= eyear, ., f);

end;

run;

proc print;run;

Haikuo

Super Contributor
Posts: 376

Re: Create, increment and use a macro variable in the same data step?

Can you describe exactly what you're trying to do?  I don't think you need macro in your example.

Quote:

          /* I want to clear fields in a column that end in '&a' */

          column1_&a = .;

          column2_&a = .;

          column3_&a = .;

Say &a=100 when the data step is compiled.  This would resolve to:

          /* I want to clear fields in a column that end in '&a' */

          column1_100 = .;

          column2_100 = .;

          column3_100 = .;

That code isn't going to change, regardless of how much you fiddle with &a.  It's already been compiled.

What about something like:

call missing(of columnSmiley Happy;

or for something more exotic (untested)

array nums column:;

do i=1 to dim(nums);

  if prxmatch("/column(\d+)_(\d+)/",vname(nums{i}) then nums{i}=.

end;

which would define an array "nums" containing all variables whose names begin with "column".  Assume they're all numeric.  Loop over the array.  If the name matches "column", a number, an underscore, and a number, then set that variable to missing.

Again, without knowing what you want to do, it's hard to supply example code.  But I suspect you don't need macro here, and you'll just tie yourself in knots if you try.

Hope this helps,

Scott

Super User
Posts: 10,476

Re: Create, increment and use a macro variable in the same data step?

If you need a variable to persist between records look at RETAIN. That is likely to do what you need within a single datastep.

Super User
Posts: 9,671

Re: Create, increment and use a macro variable in the same data step?

A call SYMPUTwill not work, Slaughter and Delwiche (2004) elaborates, "Be careful. You cannot create a macro variable with CALL SYMPUT and use it in the same DATA step.

That is true.

But there is an accident .

You can use the macro variable created by CALL SYMPUT() in the same data step when you are also using SYMGET(). Documentation has already clarified it.

15   data _null_;
16   do _n_=1 to 10 ;
17    call symputx('obs',_n_);
18    x= symget('obs');
19    put x=;
20   end;
21   run;

x=1
x=2
x=3
x=4
x=5
x=6
x=7
x=8
x=9
x=10
NOTE: DATA statement used (Total process time):
      real time           0.22 seconds
      cpu time            0.00 seconds



Ksharp

☑ This topic is SOLVED.

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

Discussion stats
  • 10 replies
  • 5984 views
  • 9 likes
  • 7 in conversation