Solved
Contributor
Posts: 35

# if then do nested within %do %end

Hi -

I want to write a code nested if then do end within the %do and %end macro, not sure how to make it work, right now my code looks like this:

%macro change;
%local n;
data want;
set data;
%do n = 0 %to 23;
if start_hour = &n. then do
inter&n = 60 - minute(start_time);
inter&n+1 = minute(stop_time);
end;
%end;
;
run;
%mend change;
%change;

The results that I want is to get the inter0 = 60-minute(start_time); inter1 = minute(stop_time); and same goes with inter1, inter2  etc.

My solution now is to write each one separately in each macro, like this: (but this does not seem to be very efficient)

%macro change;
%local n;
data want;
set one;
%do n = 0 %to 23;
if start_hour = &n. then do
inter&n. = 60 - minute(start_time);
end;
%end;
;
run;
%mend change;
%change;

%macro change;
%local n;
data one_inter;
set one_inter;
%do n = 0 %to 23;
if stop_hour = &n. then do
inter&n. = minute(stop_time);
end;
%end;
;
run;
%mend change;
%change;

Do anyone has any idea?

Thanks!

Accepted Solutions
Solution
‎07-09-2017 11:38 AM
Super User
Posts: 7,942

## Re: if then do nested within %do %end

You need to post some example data so we can understand what you are actually trying to do.

Your first macro is not going to generate SAS to do what you want.

In particular this line:

inter&n+1 = minute(stop_time);

Will generate code like:

inter0 +   1 = minute(stop_time);

Which is basically going to setup INTER0 as a count of the number of times that STOP_TIME has a value where the minute number is equal to 1.

Perhaps you meant to write:

inter&n = 60 - minute(start_time);
inter%eval(&n+1) = minute(stop_time);

But the problem with that is that then the result of your %DO would be to generate assignment statements that look like they might overwrite each other.

inter0 = 60 - minute(start_time);
inter1 = minute(stop_time);
inter1 = 60 - minute(start_time);
inter2 = minute(stop_time);

But I think the end result of this fixed macro code would really be the same thing you would get if you just used a program like this without any macro code.

data want;
set have;
array inter (0:24) inter0-inter24 ;
if 0<= start_hour <= 23 then do;
inter(int(start_hour))=60 - minute(start_time);
inter(int(start_hour)+1)=minute(stop_time);
end;
run;

Which is going to generate a strange set of mainly missing variables like:

s           s
t      s    t
a      t    a
r      o    r                                    i  i  i  i  i  i  i  i  i  i  i  i  i  i  i
t      p    t   i   i   i   i  i  i  i  i  i  i  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n
_      _    _   n   n   n   n  n  n  n  n  n  n  t  t  t  t  t  t  t  t  t  t  t  t  t  t  t
t      t    h   t   t   t   t  t  t  t  t  t  t  e  e  e  e  e  e  e  e  e  e  e  e  e  e  e
O       i      i    o   e   e   e   e  e  e  e  e  e  e  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r
b  i    m      m    u   r   r   r   r  r  r  r  r  r  r  1  1  1  1  1  1  1  1  1  1  2  2  2  2  2
s  d    e      e    r   0   1   2   3  4  5  6  7  8  9  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4

1  1   0:30   0:40  0  30  40   .   .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
2  2   2:22   5:55  2   .   .  38  55  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

All Replies
Super User
Posts: 23,346

## Re: if then do nested within %do %end

In a data step why not use a regular DO/THEN/END loop?

Contributor
Posts: 35

## Re: if then do nested within %do %end

Thar makes sense. I figure out a way to solve my problem just now, it works but maybe regular do end also work:

%macro change;
%local n;
data two_inter;
set two;
%do n = 0 %to 23;
%let m = %eval(&n+1);
if start_hour = &n. then do
inter&n = 60 - minute(start_time);
inter&m = minute(stop_time);
end;
%end;
;
run;
%mend change;
%change;
Solution
‎07-09-2017 11:38 AM
Super User
Posts: 7,942

## Re: if then do nested within %do %end

You need to post some example data so we can understand what you are actually trying to do.

Your first macro is not going to generate SAS to do what you want.

In particular this line:

inter&n+1 = minute(stop_time);

Will generate code like:

inter0 +   1 = minute(stop_time);

Which is basically going to setup INTER0 as a count of the number of times that STOP_TIME has a value where the minute number is equal to 1.

Perhaps you meant to write:

inter&n = 60 - minute(start_time);
inter%eval(&n+1) = minute(stop_time);

But the problem with that is that then the result of your %DO would be to generate assignment statements that look like they might overwrite each other.

inter0 = 60 - minute(start_time);
inter1 = minute(stop_time);
inter1 = 60 - minute(start_time);
inter2 = minute(stop_time);

But I think the end result of this fixed macro code would really be the same thing you would get if you just used a program like this without any macro code.

data want;
set have;
array inter (0:24) inter0-inter24 ;
if 0<= start_hour <= 23 then do;
inter(int(start_hour))=60 - minute(start_time);
inter(int(start_hour)+1)=minute(stop_time);
end;
run;

Which is going to generate a strange set of mainly missing variables like:

s           s
t      s    t
a      t    a
r      o    r                                    i  i  i  i  i  i  i  i  i  i  i  i  i  i  i
t      p    t   i   i   i   i  i  i  i  i  i  i  n  n  n  n  n  n  n  n  n  n  n  n  n  n  n
_      _    _   n   n   n   n  n  n  n  n  n  n  t  t  t  t  t  t  t  t  t  t  t  t  t  t  t
t      t    h   t   t   t   t  t  t  t  t  t  t  e  e  e  e  e  e  e  e  e  e  e  e  e  e  e
O       i      i    o   e   e   e   e  e  e  e  e  e  e  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r
b  i    m      m    u   r   r   r   r  r  r  r  r  r  r  1  1  1  1  1  1  1  1  1  1  2  2  2  2  2
s  d    e      e    r   0   1   2   3  4  5  6  7  8  9  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4

1  1   0:30   0:40  0  30  40   .   .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
2  2   2:22   5:55  2   .   .  38  55  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

☑ This topic is solved.