DATA Step, Macro, Functions and more

Transfer two letters to Macro

Reply
Contributor
Posts: 35

Transfer two letters to Macro

Dear all,

I wanted to transfer two letters to my macro that would be used in data step.  Such as:  I will define a macro like this:

%MACRO MyMacro(Domain=);

IF UPCASE(STRIP(&DOMAIN))='LB' THEN DO;

  LENGTH PARCAT1 $50;

  PARCAT1 = STRIP(&DOMAIN.CAT);

  END;

%MEND MyMacro;

In my program, how should I pass LB to Domain in macro?  The following way did not work.  Macro facility transfer translate &DOMAIN.CAT to 'LB'CAT.  Does any can help to overcome this?

Data abc;

     %MyMacro(Domain='LB');

run;

Thanks in advance.

Abdu

Super Contributor
Posts: 345

Re: Transfer two letters to Macro

You do not need to quote strings when using macros.

Data abc;

     %MyMacro(Domain=LB);

run;

Super User
Posts: 7,866

Re: Transfer two letters to Macro

If your intention ist to generate PARCAT1 only when DOMAIN=LB, you should rephrase it like that:

%MACRO MyMacro(Domain=);

%IF %UPCASE(&Domain)=LB %THEN %DO;

  LENGTH PARCAT1 $50;

  PARCAT1 = STRIP(&DOMAIN.CAT);

%END;

%MEND MyMacro;

options mlogic mprint;

Data abc;

lbcat = 'XXX';

     %MyMacro(Domain=LB);

     %MyMacro(Domain=LC); * just to show what happens;

run;

options nomlogic nomprint;

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Contributor
Posts: 35

Re: Transfer two letters to Macro

Posted in reply to KurtBremser

Hi Kurt/Andreas,

Because I am using the macro in data step, if I call macro like %MyMacro(Domain=LB); I will get an LB uninitial message, and the letter LB was not passed to macro facility.  I temporally using this way:

LENGTH LB $2;

LB='LB'; *LB=anything may work as well;

%MyMacro(Domain=LB);

But I think there should be other professional way to pass LB to the macro.

Another thing bothers me is like Kurt suggested:

%IF %UPCASE(&Domain)=LB %THEN %DO;

  LENGTH PARCAT1 $50;

  PARCAT1 = STRIP(&DOMAIN.CAT);

%END;

I still get missing values for PARCAT1 if I run it with other domain.  I guess it is difficult to discard PARCAT1 if I am not working with LB domain.  Any suggestions?

Thanks for responding.,

Abdu

Super User
Posts: 5,518

Re: Transfer two letters to Macro

When you refer to a macro variable, you have the option of adding a dot at the end of the name.  Both of these resolve to the same thing:

&DOMAIN

&DOMAIN.

If you want a dot added to your program, use two dots:

&DOMAIN..CAT

Good luck.

Contributor
Posts: 35

Re: Transfer two letters to Macro

Posted in reply to Astounding

Hi Astounding,

I actually want to combine the two part without period in the middle.

Thanks,,

Abdu

Super User
Posts: 5,518

Re: Transfer two letters to Macro

In that case, you should without question pass the value without quotes:

(domain=LB)

The more difficult question is what should the SAS code look like that is generated by macro language?  For example, do you want the SAS program to contain:

PARCAT1="LBCAT";

Or do you want it to contain:

PARCAT1=LBCAT;

That's pretty much the question for any macro language application:  what do you want the generated SAS code to look like?

Contributor
Posts: 35

Re: Transfer two letters to Macro

Posted in reply to Astounding

I want to generate SAS code like:

PARCAT1=LBCAT;

Please view my previous response to Kurt/Andreas. My trouble part is how to pass 'LB' to macro in data step.  I guess I can write an independent macro, but I think a macro used in data step is easier to apply and less trouble.

Thanks, 

Super User
Posts: 5,518

Re: Transfer two letters to Macro

Looking that over, it looks like your macro definition should be different.  Use macro %IF/%THEN instead of DATA step IF/THEN:

%if &domain=LB %then %do;

   length parcat1 $ 50;

   parcat1=LBCAT;

%end;

Or, if appropriate, don't use any form of IF/THEN statements:

length parcat1 $ 50;

parcat1=&domain.CAT;

As before, the real issue is what the SAS code is supposed to look like when you call the macro.

Super User
Super User
Posts: 7,997

Re: Transfer two letters to Macro

Well,

options mlogic mprint symbolgen;
%MACRO MyMacro(Domain=);
  %IF %sysfunc(upcase(&DOMAIN.))=LB %THEN %DO;
    LENGTH PARCAT1 $50;
    PARCAT1 = STRIP(&DOMAIN.CAT);
  %END;
%MEND MyMacro;

Data abc;
     %MyMacro(Domain=LB);
run;

However I agree with Astounding what do you want the code to look like, maybe post the whole section of code so we can see context for this.  Assuming it is SDTM why would you want to strip only if domain is LB?  Why also would parcat1 only be assigned a length is domain=lb?

Contributor
Posts: 35

Re: Transfer two letters to Macro

Thank you, RW9.

Here is my working code.  I want to resolve two non-professional part:

1. Pass 'LB' in better way.

2. If Domain ne 'LB', I won't generate PARCAT1. (For example, in VS domain, I do not need PARCAT1 variable)

===============

%MACRO BASEANVARS(DOMAIN=);

  IF CMISS(&DOMAIN)=1 THEN DO;

  PUT "NOTE: YOU NEED TO SPECIFY TWO-CHAR DOMAIN NAME. NO VARIABLES GENERATED!";

  STOP ;

  END;

  LENGTH PARAM AVALC $200 PARAMCD $8;

  IF STRIP(&DOMAIN.STRESU) = '' THEN PARAM = STRIP(COMPBL(&DOMAIN.TEST));

  ELSE PARAM = CATT(STRIP(COMPBL(&DOMAIN.TEST)),' (', STRIP(&DOMAIN.STRESU),')');

  IF CMISS(&DOMAIN.TESTCD)=0 THEN PARAMCD=STRIP(&DOMAIN.TESTCD);

  IF UPCASE(STRIP(&DOMAIN))='LB' THEN DO;

  LENGTH PARCAT1 $50;

  PARCAT1 = STRIP(&DOMAIN.CAT);

  END;

  *Analysis Values;

  AVAL  = &DOMAIN.STRESN;

  AVALC = STRIP(&DOMAIN.STRESC);

  IF CMISS(&DOMAIN.DTC)=0 THEN DO; %ISOtoDTM2(ISODTC=&DOMAIN.DTC, ADate=ADT, ATime=ATM, Rule=0); END;

  IF CMISS(ADT, TRTSDT) = 0 THEN ADY = ADT - TRTSDT + (ADT >= TRTSDT);

%MEND BASEANVARS;

DATA _LB_1;

  MERGE ADSL _LB_S;

  BY USUBJID;

  IF STRIP(UPCASE(LBSTAT)) = 'NOT DONE' THEN DELETE;

  FORMAT ADT DATE9. ATM TIME5.;

  LENGTH LB $2;

  LB='LB';

  %BASEANVARS(DOMAIN=LB);

RUN;

======================

I guess in data step, I can not use %if ... %then...

Thanks

Super User
Super User
Posts: 7,997

Re: Transfer two letters to Macro

So your creating Adam's based of the base dataset model.  Mmm, gotta say this wouldn't be my way of doing it.  I would create the spec first, generally in Excel so one tab per domain with variables formats etc.  Then I read this in and generate the program from there.  With that there is no need to decide what variables are present, or the other various conditionals.  At the end of the day if you have well presented specs, which are approved by the team, the actual coding is negligible (ok, maybe some of the mappings can get a bit complicated).  I did some months back demonstrate a system where metadata is stored in Excel in spec format so reviewable.  With this and a generic code generator was able to create RAW->SDTM->ADAM->TLF Datasets->Output with no actual coding whatsoever.  Just a generic loop over metadata.

Contributor
Posts: 35

Re: Transfer two letters to Macro

Thank you for sharing your idea and way to do it.  My thinking is, the specs are different depends on study and statistician.   So that is why I made my Macro very small, part by part.  Many variables specs are same.  For the differences, I just need to modify my mall part.  It is easy to apply and maintain.

My Question is still there: How do I pass DAMAIN=LB to macro?  If I do not define LB as a variable in data step, that will give me a LB uninitialized warning.

Thanks,

Super User
Posts: 5,518

Re: Transfer two letters to Macro

You call the macro in this fashion:

%mymacro (domain=LB)

From that point, it is up to you to verify that the DATA step code does not mention a variable named LB.  It is only the generated DATA step code that determines whether a variable LB gets created (whether initialized or uninitialized).  So if your generated DATA step code contains a statement like this, you may get such a message:

newvar = LB;

You have to control the generated DATA step code so that it has the correct syntax and only creates the needed variables.

Super User
Posts: 5,518

Re: Transfer two letters to Macro

Assuming you keep this approach in place, definitely expect to call the macro using DOMAIN=LB ... no quotes needed.

Here are a few suggestions.

A better test for a two-character value would be:

if length("&domain") ne 2 then do;

Checking for missing values does not require the STRIP function.  A simpler version:

if &domain.stresu = ' ' then param= ...

The LENGTH statement cannot be executed conditionally.  If it appears in the program, you will always be open to getting messages about a variable being uninitialized.  So you can use macro language to control whether or not your DATA step will contain a LENGTH statement:

%if &domain=LB %then %do;

   ... as detailed in earlier post;

%end;

You cannot use %IF/%THEN as statements that execute within a DATA step.  But you can certainly use %IF/%THEN as statements to control whether or not certain statements will be generated as part of the DATA step.

Finally (if appropriate for this application) most comparisons will not need a STRIP function.  Unless you have leading blanks in some character strings, STRIP is hardly ever needed.  SAS knows how to handle trailing blanks when making a comparison of character strings without the need for functions.

Good luck.


Ask a Question
Discussion stats
  • 19 replies
  • 477 views
  • 6 likes
  • 7 in conversation