BookmarkSubscribeRSS Feed
Abdu
Calcite | Level 5

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

19 REPLIES 19
andreas_lds
Jade | Level 19

You do not need to quote strings when using macros.

Data abc;

     %MyMacro(Domain=LB);

run;

Kurt_Bremser
Super User

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;

Abdu
Calcite | Level 5

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

Astounding
PROC Star

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.

Abdu
Calcite | Level 5

Hi Astounding,

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

Thanks,,

Abdu

Astounding
PROC Star

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?

Abdu
Calcite | Level 5

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, 

Astounding
PROC Star

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.

RW9
Diamond | Level 26 RW9
Diamond | Level 26

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?

Abdu
Calcite | Level 5

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

RW9
Diamond | Level 26 RW9
Diamond | Level 26

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.

Abdu
Calcite | Level 5

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,

Astounding
PROC Star

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.

Astounding
PROC Star

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.


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
  • 19 replies
  • 1425 views
  • 6 likes
  • 7 in conversation