BookmarkSubscribeRSS Feed
PaigeMiller
Diamond | Level 26

@Onizuka wrote:

Thank you Amir,

 

I believe that I have understood. When using a variable macro the % must be used and if not removed.

 

I think I could have written this :

 

/* if i take off the macro variable */	
%macro test ;
....
Data blabla;
set blabla1
...
DO i=1 TO 10; IF tquestcourt[&i] ne . THEN do ; test=test+1; end ; END; ...
run ;

%mend test ; /*if i add the macro variable */ %DO i=1 %TO &nbvar.; IF tquestcourt[&i] ne . THEN do ; test=test+1; end ; %END;

Am I right ? haha


There is absolutely no benefit to adding a macro %DO loop here when you could and should use the data step DO loop.

--
Paige Miller
Onizuka
Pyrite | Level 9

Ok, it also worked by removing the % .. I'm a little lost i have to admit

 

I thought that when we are in a macro program we must put % everywhere

 

PaigeMiller
Diamond | Level 26

@Onizuka wrote:

Ok, it also worked by removing the % .. I'm a little lost i have to admit

 


Data steps work just fine without any % signs. You need to become 100% clear about what the difference between macro code and data step code is.

 

Macro language results in text substitution. It replace some text (for example, &I) with its value (for example, 3). You don't need text substitution here, because everything written in data step language in this case works properly.

 

As stated earlier, get the program to work on one example or one iteration without macros and without macro variables. Then only add macros if what you need can't be done any other way.

 

Also

 

%IF tquestcourt[&i] ne . %THEN %DO ;

the %IF means that the macro processor now is NOT looking for data step variables and their values. It does not know the value of TQUESTCOURT. It thinks that tquestcourt[&i] ne . is some text string, and it does not use the data set variable values. That is why you must use IF and not %IF here.

I thought that when we are in a macro program we must put % everywhere

 

A terrible concept, that will mislead you and cause many problems in your future. Never think this way again. Please think about the concepts that @Tom and I and others have stated here.

 

--
Paige Miller
gamotte
Rhodochrosite | Level 12

Anytime you use a macro, you have to ask yourself : what will my program become

once every macro element has been resolved ?

 

For instance, your loop :

 

%DO i=1 %TO &nbvar.;
 		IF tquestcourt[&i] ne . THEN do ; 
		test=test+1; 
		end ;
	%END;

will generate the following code :

 

 if tquestcourt[1] ne . then do ; test=test+1; end ;
 if tquestcourt[2] ne . then do ; test=test+1; end ;
 if tquestcourt[3] ne . then do ; test=test+1; end ;
 [...] /* &nbvar. times */

So your macro code does not mean loop through the array elements but copy/paste the same code

&nbvar. times increasing &i. at each paste. An array loop uses do ... end withous the %.

 

do i=1 to dim(tquestcourt);
    if tquestcourt[i] ne . then do ; test=test+1; end ;
end;

Note that this will create a new column i in your dataset.

Onizuka
Pyrite | Level 9

@gamotte wrote:

 

For instance, your loop :

 

%DO i=1 %TO &nbvar.;
 		IF tquestcourt[&i] ne . THEN do ; 
		test=test+1; 
		end ;
	%END;

will generate the following code :

 

 if tquestcourt[1] ne . then do ; test=test+1; end ;
 if tquestcourt[2] ne . then do ; test=test+1; end ;
 if tquestcourt[3] ne . then do ; test=test+1; end ;
 [...] /* &nbvar. times */

So your macro code does not mean loop through the array elements but copy/paste the same code

&nbvar. times increasing &i. at each paste. An array loop uses do ... end withous the %.

 

do i=1 to dim(tquestcourt);
    if tquestcourt[i] ne . then do ; test=test+1; end ;
end;

Note that this will create a new column i in your dataset.


 

Okey, thank you, i didn't know that (about the copy paste of the same code).

 

@PaigeMiller  I do not understand exactly what your program does...I'm going home now so I will study all this tomorrow, thank you for your time and maybe see you tomorrow ! 🙂

 

 

PaigeMiller
Diamond | Level 26

When &category=BOAT, this code is generated

 

    data want;
        set mydataset;
        newvar = x2 + x7;
        keep id x1-x7 newvar;
    run;

When &category^=BOAT, this code is generated

 

    data want;
        set mydataset;
        keep id x1-x7;
    run;

So the use of the macro variable causes different SAS code to be generated, depending on the value of the macro variable.

--
Paige Miller
Onizuka
Pyrite | Level 9

@PaigeMiller wrote:

When &category=BOAT, this code is generated

 

    data want;
        set mydataset;
        newvar = x2 + x7;
        keep id x1-x7 newvar;
    run;

When &category^=BOAT, this code is generated

 

    data want;
        set mydataset;
        keep id x1-x7;
    run;

So the use of the macro variable causes different SAS code to be generated, depending on the value of the macro variable.


Okeeeey, I have understood, thank you very much for these exaplanations !

 

Does everything that works in "basic" sas language also works in macro language?

gamotte
Rhodochrosite | Level 12

Does everything that works in "basic" sas language also works in macro language?


It is not clear what you mean by that. This is not an either...or situation : utimately, the compilation phase will interpret all macro instructions and generate a 100% "basic" sas language for execution (the order of operations can be a bit more complex e.g. when you have call symput's but you get the idea).

Think of macro language as a way to parameterize a sas program and to reuse the same code portions in several places without having to rewrite all the code.

 

Now, if your question is : can functions available in a datastep to manipulate column values also be used to modify macrovariable values ?

There are some functions, like substr for instance, that have a macro language equivalent :

%let str=hello !;
%let str2=%substr(&str.,2);
%put &=str2;

 

http://support.sas.com/documentation/cdl/en/allprodslang/63337/HTML/default/viewer.htm#syntaxByType-...

 

Other does not have a direct macro equivalent but can still be used using %sysfunc :

%let str=a b c;
%let nbelt=%sysfunc(countw(&str.));
%put &=nbelt;

 

http://support.sas.com/documentation/cdl/en/mcrolref/62978/HTML/default/viewer.htm#p1o13d7wb2zfcnn19...

Onizuka
Pyrite | Level 9

Hello @gamotte ,

 

Thank you for you answer.

 

I think I'm starting to understand how the macro works.

 

I took a code I had in which I repeated several times the same instruction but with different variables. I used the macro language to "reduce" the code as you can see below:

 

data test_hierarchie ;
set mdv.hierarchie ;
          _COD_ETB = input(COD_ETB, $15.);
_COD_EDS_EXTR_NIV1 = input(COD_EDS_EXTR_NIV1, $15.);
_COD_EDS_EXTR_NIV2 = input(COD_EDS_EXTR_NIV2, $15.);
_COD_EDS_EXTR_NIV3 = input(COD_EDS_EXTR_NIV3, $15.);
_COD_EDS_EXTR_NIV4 = input(COD_EDS_EXTR_NIV4, $15.);
_COD_EDS_EXTR_NIV5 = input(COD_EDS_EXTR_NIV5, $15.);
_COD_EDS_EXTR_NIV6 = input(COD_EDS_EXTR_NIV6, $15.);
_COD_EDS_EXTR_NIV7 = input(COD_EDS_EXTR_NIV7, $15.);
_COD_EDS_EXTR_NIV8 = input(COD_EDS_EXTR_NIV8, $15.);
 		  _LIB_ETB = put(LIB_ETB, $50.);
 _LIB_EDS_INT_NIV1 = put(LIB_EDS_INT_NIV1,$50.) ;
 _LIB_EDS_INT_NIV2 = put(LIB_EDS_INT_NIV2,$50.) ; 
 _LIB_EDS_INT_NIV3 = put(LIB_EDS_INT_NIV3,$50.) ;
 _LIB_EDS_INT_NIV4 = put(LIB_EDS_INT_NIV4,$50.) ;
 _LIB_EDS_INT_NIV5 = put(LIB_EDS_INT_NIV5,$50.) ;
 _LIB_EDS_INT_NIV6 = put(LIB_EDS_INT_NIV6,$50.) ;
 _LIB_EDS_INT_NIV7 = put(LIB_EDS_INT_NIV7,$50.) ;
 _LIB_EDS_INT_NIV8 = put(LIB_EDS_INT_NIV8,$50.) ;
run ;

Proc sql ;
create table test_hierarchie1 as
select 
	 NBNIV,
	 CleEDS,
	 _LIB_ETB as lib_plus_grd,
	 _LIB_EDS_INT_NIV1 as lniv1,
	 _LIB_EDS_INT_NIV2 as lniv2,
	 _LIB_EDS_INT_NIV3 as lniv3,
	 _LIB_EDS_INT_NIV4 as lniv4,
	 _LIB_EDS_INT_NIV5 as lniv5,
	 _LIB_EDS_INT_NIV6 as lniv6,
	 _LIB_EDS_INT_NIV7 as lniv7,
	 _LIB_EDS_INT_NIV8 as lniv8,

	 _COD_ETB as niveau_plus_grd,
	 _COD_EDS_EXTR_NIV1 as cniv1,
	 _COD_EDS_EXTR_NIV2 as cniv2,
	 _COD_EDS_EXTR_NIV3 as cniv3,
	 _COD_EDS_EXTR_NIV4 as cniv4,
	 _COD_EDS_EXTR_NIV5 as cniv5,
	 _COD_EDS_EXTR_NIV6 as cniv6,
	 _COD_EDS_EXTR_NIV7 as cniv7,
	 _COD_EDS_EXTR_NIV8 as cniv8
from test_hierarchie ;
run ;

(These two codes are in a macro.)

I have transformed these two codes like this :

 

Data test (keep = nbniv cleEDS lib_plus_grd lniv: niveau_plus_grd cniv:);
Set mdv.hierarchie ;

	%do i = 1 %to 8 ;

		_COD_EDS_EXTR_NIV&i = input(COD_EDS_EXTR_NIV&i, $15.);

		_LIB_EDS_INT_NIV&i = put(LIB_EDS_INT_NIV&i,$50.) ;

		rename _LIB_EDS_INT_NIV&i = lniv&i ;

		rename _COD_EDS_EXTR_NIV&i = cniv&i ;

	%end ;

   		_COD_ETB = input(COD_ETB, $15.);

		_LIB_ETB = put(LIB_ETB, $50.);

		rename _COD_ETB = niveau_plus_grd ;

		rename _LIB_ETB = lib_plus_grd ;		 
run ;


data test1 ;
retain nbniv cleEDS lib_plus_grd lniv1-lniv8 niveau_plus_grd cniv1-cniv8 ;
set test ;
run ;

Is this a good use of macro ? (I don't ask you to rewrite my code but just tell if the use of macro language is appropriate here).

 

 

Tom
Super User Tom
Super User

If you want to write MACRO logic then you use the macro commands: %IF, %DO etc.

If you want to write SAS logic then you use the SAS commands: IF, DO etc.

 

The macro processor will execute the macro logic and the resulting code (text) will be sent to SAS to interpret and execute.

 

When thinking about what macro logic does think about it in terms of what CODE it generates.

When thinking about what SAS logic does think about it in term of what DATA It generates.

Onizuka
Pyrite | Level 9

Ok, so when we are in a Data step, we don't need to use %DO %IF etc. We should use the macro language when we are NOT in a data step. You agree ?

 

Like on this macro I have created which permit to execute my "long" macro programm :

 

%MACRO RUN_CIM_EER_EV (typequest =);

%LET date_fin_trim_precedent = %SYSFUNC(mdy(&mois_fin_trim_precedent.,&jour_fin_trim_precedent.,&annee_fin_trim_precedent.));
%LOCAL i ;
%DO i = 1 %TO %SYSFUNC(countw(&typequest));

%LET nextvar 	= %SCAN(&typequest, &i);		

			%CIM_EER_EV (typequest 				  = &nextvar
						,chemin_fichier			  = &chemin_fichier
						,jour_fin_trim_precedent  = &jour_fin_trim_precedent
						,mois_fin_trim_precedent  = &mois_fin_trim_precedent
						,annee_fin_trim_precedent = &annee_fin_trim_precedent)
	
%END ;

%MEND RUN_CIM_EER_EV ;

 

PaigeMiller
Diamond | Level 26

@Onizuka wrote:

Ok, so when we are in a Data step, we don't need to use %DO %IF etc. We should use the macro language when we are NOT in a data step. You agree ?


Sorry, no that's not right either.

 

Macro language can be used in a data step when you need it to do macro things, essentially text substitution. Macro language can also be used outside of a data step.

 

Again, you need to understand, as @Tom has pointed out, when you are working with the code and need macro functionality, and when you are working with the data in a data set, in which case you don't need macros. As I have stated twice previously, get your code to work without macro variables on one instance or one iteration, and then only if non-macro code won't get you to the final result, then use macro language.

--
Paige Miller
Onizuka
Pyrite | Level 9

I understand what you say even if this difference of synthax (macro language and "basic-language") is not yet completely clear to me.

 

For the context, know that I realized a macro program and not "basic" sas codes because the program must be run several times (once per file) and so it seemed faster to do that like that.

 

When i'm writting this (for example) :

 

%macro test (var=) ;

Data one ;
set two ;
if &var = 10 ;
run ;

%Mend test ;

%test(var = B)

You agree that this is a macro programm ? which is using a macro variable ?

 

what I have trouble understanding is precisely the difference between manipulating code and manipulating data. Because for me, the code allows to manipulate data (create columns, variables, transform variables etc)

 

Sorry if I make you lose patience ..

PaigeMiller
Diamond | Level 26

Yes, that seems like a valid use of a macro variable within a data step, where now the actual data step code is changed depending on what value &VAR has.

 

Here's another example, something from my work, where &category can contain values RV, AUTO, BOAT

 

%macro dothis(category=);
    data want;
        set mydataset;
        %if &category=BOAT %then
             newvar = x2 + x7 %str(;) ;
        keep id x1-x7 %if &category=BOAT %then newvar; ;
    run;
%mend;

Different SAS data step code is created depending on the value of &category. The use of macro language causes the code to change.

--
Paige Miller
gamotte
Rhodochrosite | Level 12

When you write a SAS program, if you find that you often have to copy /paste the same large code portion and make minor changes, there is a chance that you can use a macro function to reduce the program size and make it more readable and less error prone.

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 29 replies
  • 1619 views
  • 11 likes
  • 6 in conversation