BookmarkSubscribeRSS Feed
trekvana
Calcite | Level 5
Hello all,

here is my macro code:

%macro sc(i,resdata);
proc iml;
start delcol(x,i);
return(x[,setdif(1:ncol(x),i)]);
finish;

use test&i;
read all into x;
x=delcol(x,{1,2}); print x;

use &resdata;
read all var {Resid} into y where(id=(&i+1) & Resid^=.); print y;

sc=x*y; print sc;
create newdata&i from sc;
append from sc;
close newdata&i;
quit;
%mend;

I want to loop this macro for different values of i:

do i=1 to 38;
%sc(i,hala);
end;

Essentially the sc macro creates a new data set everytime it runs so I want to run it 38 times but I'm not sure how to code my loop to work on its own.

Suggestions?
15 REPLIES 15
sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10
You would have an outside macro to control / execute 38 times using a %DO I=1 %TO 38; %END; and where you call your %SC macro, you would include the macro variable reference &I to resolve a numeric value with each iteration.

Include the command below to get additional SASLOG diagnostics output generated with your macro execution / compilation phase (also you can include additional parameters SYMBOLGEN MLOGIC for debugging purposes):

OPTIONS SOURCE SOURCE2 MACROGEN MPRINT;


Scott Barry
SBBWorks, Inc.

Suggested Google advanced search arguments, this topic / post:

macro introduction site:sas.com

macro variables introduction site:sas.com

macro debugging site:sas.com
trekvana
Calcite | Level 5
Scott, is this what you mean?

%macro blah;
%do i = 1 %to 38;
%sc(i,hala);
%end;
%mend;

Also Im not sure how I would create a macro variable reference for &i

Message was edited by: trekvana Message was edited by: trekvana
sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10
No - I mentioned that you need to use the SAS macro variable, &I -- what you have coded is a literal character "i" which will not resolve the number value you want with each %DO / %END iteration.

That is also why I suggested the diagnostic OPTIONS statement to you to help learn about using macro variables, as well as the DOC references.

Scott Barry
SBBWorks, Inc.
trekvana
Calcite | Level 5
Ah ok!.

Thanks Scott
trekvana
Calcite | Level 5
Dear Scott,

So here is my new macro:

%macro nprme;
%do i = 1 %to 2;
%sc(&i,hala);
%end;
OPTIONS SOURCE SOURCE2 MACROGEN MPRINT;
%mend nprme;

Now when I run my macro with %nprme I get this log:
1645 %macro nprme;
1646 %do i = 1 %to 2;
1647 %sc(&i,hala);
1648 %end;
1649 OPTIONS SOURCE SOURCE2 MACROGEN MPRINT;
1650 %mend nprme;
1651
1652 %nprme
MPRINT(SC): proc iml;
NOTE: IML Ready
MPRINT(SC): start delcol(x,i);
MPRINT(SC): return(x[,setdif(1:ncol(x),i)]);
MPRINT(SC): finish;
NOTE: Module DELCOL defined.
MPRINT(SC): use test1;
MPRINT(SC): read all into x;
MPRINT(SC): x=delcol(x,{1,2});
MPRINT(SC): print x;
MPRINT(SC): use hala;
MPRINT(SC): read all var {Resid} into y where(id=(1+1) & Resid^=.);
MPRINT(SC): print y;
MPRINT(SC): sc=x*y;
MPRINT(SC): print sc;
MPRINT(SC): create newdata1 from sc;
MPRINT(SC): append from sc;
MPRINT(SC): close newdata1;
NOTE: The data set WORK.NEWDATA1 has 7 observations and 1 variables.
MPRINT(SC): end;
ERROR: END does not occur within DO group at line=3391 col=86.
MPRINT(SC): quit;
NOTE: Exiting IML.
NOTE: PROCEDURE IML used (Total process time):
real time 0.17 seconds
cpu time 0.01 seconds


MPRINT(NPRME): ;
MPRINT(SC): proc iml;
NOTE: IML Ready
MPRINT(SC): start delcol(x,i);
MPRINT(SC): return(x[,setdif(1:ncol(x),i)]);
MPRINT(SC): finish;
NOTE: Module DELCOL defined.
MPRINT(SC): use test2;
MPRINT(SC): read all into x;
MPRINT(SC): x=delcol(x,{1,2});
MPRINT(SC): print x;
MPRINT(SC): use hala;
MPRINT(SC): read all var {Resid} into y where(id=(2+1) & Resid^=.);
MPRINT(SC): print y;
MPRINT(SC): sc=x*y;
MPRINT(SC): print sc;
MPRINT(SC): create newdata2 from sc;
MPRINT(SC): append from sc;
MPRINT(SC): close newdata2;
NOTE: The data set WORK.NEWDATA2 has 8 observations and 1 variables.
MPRINT(SC): end;
ERROR: END does not occur within DO group at line=3404 col=86.
MPRINT(SC): quit;
NOTE: Exiting IML.
NOTE: PROCEDURE IML used (Total process time):
real time 0.17 seconds
cpu time 0.03 seconds


MPRINT(NPRME): ;
MPRINT(NPRME): OPTIONS SOURCE SOURCE2 MACROGEN MPRINT;

So it seems like the iterations are working and the data sets are also being created but I am confused about that error message. Any insight? Ok I see what is happening. The loop is adding the END statement right before the QUIT statement in the SC macro. Is that a problem. Looking at the new data sets everything looks good

Message was edited by: trekvana
sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10
I don't see your SC macro definition in your pasted log (the most recent reply) -- you need to investigate whether there is or is not an END; statement defined inside the SC macro before the QUIT statement, in your complete SAS program. If not coded, then you should either contact SAS Tech Support or post over in the IML forum and provide a reference (hyperlink) back to this post-thread -like this:

http://support.sas.com/forums/thread.jspa?messageID=42237


Note: it's important to share *ALL* of your code in this type of situation.

Scott Barry
SBBWorks, Inc.
art297
Opal | Level 21
Trekvana,

Like Scott I don't know what your code actually looks like. Is %SC calling a macro called SC? If so, your ending those lines with a semi-colon COULD be the cause of your problem.

Art
trekvana
Calcite | Level 5
Here is my complete situation: I am using proc mixed to get the choleski inverses of all my subject covariance matricies and then using my macro to do some matrix computation with the residual vectors in the OUTPM data set.

proc mixed data=weight;
class id week;
model weight=cweek / outpm=hala vciry;
repeated week / type=ar(1) subject=id rci=1 to 38;
ods output InvCholR(match_all)=test;
run;

%macro sc(i,resdata);
proc iml;
start delcol(x,i);
return(x[,setdif(1:ncol(x),i)]);
finish;

use test&i;
read all into x;
x=delcol(x,{1,2}); print x;

use &resdata;
read all var {Resid} into y where(id=(&i+1) & Resid^=.); print y;

sc=x*y; print sc;
create newdata&i from sc;
append from sc;
close newdata&i;
quit;
%mend sc;

Then I run the macro through my subjects with:

%macro nprme;
%do i = 1 %to 37;
%sc(&i,hala);
%end;
OPTIONS SOURCE SOURCE2 MACROGEN MPRINT;
%mend nprme;

%nprme
trekvana
Calcite | Level 5
Dear Art,

you were correct. Once I removed the semi colon from the %sc(&i,resdata):

%macro nprme;
%do i = 1 %to 37;
%sc(&i,hala)
%end;
%mend nprme;

the error code was resolved. I guess I got confused because I thought all statements within a DO loop had to be ended with semi-colons.
ArtC
Rhodochrosite | Level 12
Statements do end with semi-colons. Macro calls do not. effectively the semi-colon that followed the macro call was inserted after the QUIT;. The QUIT became:
[pre]
quit;;[/pre]

Generally a semi-colon by itself (or inthis case a double semi-colon) is not a problem. I do not use IML much and am unsure why it would be a problem here.

a different Art
Cynthia_sas
SAS Super FREQ
Hi:
ArtC is correct that macro calls generally do not end with a semi-colon. However, in some instances when using SAS/IntrNet or a stored process as part of the SAS Platform for Business Analytics, there are some macro calls that DO end with a semi-colon. I just wanted to get that out in the forum before a gazillion stored process programmers started taking the semi-colon off of %STPBEGIN; calls.

cynthia
art297
Opal | Level 21
Cynthia,

I hope your post negates the gazillion or so programmers doing what they shouldn't do, but my original suggestion was based on an old SAS-L post I recalled where the opposite result was obtained.

My point: it sure helps to know, as part of one's learning, how semicolons can affect macros.

For example, try the following two runs (where the presence or absence of the semicolon is INSIDE the macro:)

%MACRO FUNC(MONTH);
SUBSTR(PUT(&MONTH,Z6.),1,4)*12 +
SUBSTR(PUT(&MONTH,Z6.),5,2)*1;
%MEND;


DATA TEST;
M1=200901; M2=200705;
DIFF=%FUNC(M1)-%FUNC(M2);
RUN;

which will, of course, result in an error, while the following one will run without any problem (other than, of course, the notes about converting text to numbers):

%MACRO FUNC(MONTH);
SUBSTR(PUT(&MONTH,Z6.),1,4)*12 +
SUBSTR(PUT(&MONTH,Z6.),5,2)*1
%MEND;


DATA TEST;
M1=200901; M2=200705;
DIFF=%FUNC(M1)-%FUNC(M2);
RUN;

I don't want to be too critical, but it would have been nice if the developers of built-in SAS macros had followed the same protocol that has been ingrained into the rest of us.

Art
Cynthia_sas
SAS Super FREQ
Art:
I understand what you're saying, but I think the developers were true to the fundamental nature of the macro facility when they built in that behavior. A SAS macro program can generate entire multi-step progarms, single step programs, parts of steps, entire statements, parts of statements or a single character. Whether or not you put a semi-colon in your macro program, especially when you are generating parts of statements really, really depends on what you are trying to have be resolved into code.

The SAS Macro facility doesn't technically "execute" anything and when a macro program is invoked, it doesn't technically "execute" it only resolves macro triggers and macro variable references and after it is done with all the resolving and building of code, the built code goes forward to the compiler.

That's why I call the SAS Macro facility a "big typewriter" -- all it's doing is typing code for me. Which is why I ALWAYS recommend that you start with a working SAS program. If I had been writing your macro, I would have started with a working program like this:
[pre]
DATA TEST;
M1=200901;
M2=200705;

DIFF=(SUBSTR(PUT(m1,Z6.),1,4)*12 + SUBSTR(PUT(m1,Z6.),5,2)*1) -
(SUBSTR(PUT(m2,Z6.),1,4)*12 + SUBSTR(PUT(m2,Z6.),5,2)*1 ) ;

RUN;
[/pre]

The semi-colon at the end of the assignment statement is the ONLY semi-colon that's needed. So, if I am writing a macro program to "type" this for me (shown once for M1):
[pre]
(SUBSTR(PUT(m1,Z6.),1,4)*12 + SUBSTR(PUT(m1,Z6.),5,2)*1)
[/pre]

...then it would be inappropriate to even put a semi-colon inside the macro program definition. If you turn on the debugging options MPRINT SYMBOLGEN and MLOGIC, you can see in the SAS log, that all the macro facility is doing is typing parts of statements to go forward to the compiler:
[pre]
978 DATA TEST;
979 M1=200901; M2=200705;
980 DIFF=%FUNC(M1)-%FUNC(M2);
MLOGIC(FUNC): Beginning execution.
MLOGIC(FUNC): Parameter MONTH has value M1
SYMBOLGEN: Macro variable MONTH resolves to M1
SYMBOLGEN: Macro variable MONTH resolves to M1
MPRINT(FUNC): SUBSTR(PUT(M1,Z6.),1,4)*12 + SUBSTR(PUT(M1,Z6.),5,2)*1 < -- here
MLOGIC(FUNC): Ending execution.
MLOGIC(FUNC): Beginning execution.
MLOGIC(FUNC): Parameter MONTH has value M2
SYMBOLGEN: Macro variable MONTH resolves to M2
SYMBOLGEN: Macro variable MONTH resolves to M2
MPRINT(FUNC): SUBSTR(PUT(M2,Z6.),1,4)*12 + SUBSTR(PUT(M2,Z6.),5,2)*1 < -- and here
MLOGIC(FUNC): Ending execution.
981 RUN;
[/pre]

And these days, with PROC FCMP, I probably wouldn't do this type of thing in a macro program anyway. Truth be told, if all I wanted was the difference between 2 dates, I would have used the INTCK function.
[pre]
DATA calcdur;
M1=200901;
M2=200705;

DIFF=(SUBSTR(PUT(m1,Z6.),1,4)*12 + SUBSTR(PUT(m1,Z6.),5,2)*1) -
(SUBSTR(PUT(m2,Z6.),1,4)*12 + SUBSTR(PUT(m2,Z6.),5,2)*1) ;
put m1= m2= diff=;

date1 = input(put(m1,6.),yymmn6.);
date2 = input(put(m2,6.),yymmn6.);
month_diff = intck('month',date2,date1);
put date1= date2= month_diff=;
RUN;

ods listing;
proc print data=calcdur;
var m1 date1 m2 date2 diff month_diff;
format date1 date2 yymmn6.;
run;
[/pre]

cynthia
chang_y_chung_hotmail_com
Obsidian | Level 7
Hi, Cynthia:

You are making many good points but most are irrelevant to the one Art is making. Only the relevant point seems to be:

> Whether or not you put a semi-colon in your macro program, especially when you are
> generating parts of statements really, really depends on what you are trying to
> have be resolved into code.

And I don't think you are right.

If you are not generating a complete statement in your macro, then you should not include a semi-colon in the macro. If you *are* generating a complete statement in your macro, you *should* include a semi-colon, as well. Otherwise, it simply does not make sense at all.

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
  • 15 replies
  • 1222 views
  • 0 likes
  • 6 in conversation