SAS Programming

DATA Step, Macro, Functions and more
BookmarkSubscribeRSS Feed
Haris
Lapis Lazuli | Level 10

I am looking to modify macro parameters using %IF %THEN conditional macro language.  Unfortunately, conditional macro language cannot be used as part of another macro's parameter specification.

 

This community has been an invaluable resource.  Can I ask for ideas how to proceed?  I know I can do CASE WHEN and condition it on variable DV that way; however, the lists can be long and differ by one number most of the time.  I'd hate to type them out twice and open the door for errors in the future edits.

 

In the example below, both Pt 1 and 2 should get value 1=Yes while both Pt 3 and 4should get 0=No.

- Pt=1 has both Proc=1 and Proc=2. 

- Pt=2 has Proc=1 and (Proc=3 AND DV<6)

- Pt=3 has Proc=1 and Proc=3 but DV>6.

- Pt=4 has Proc=1 but no Proc=2 OR Proc=3 even though DV<6.

 

data x;input Pt Proc DataVrsn @@;cards;1 1 6 1 2 6 1 4 6 2 1 5 2 3 5 2 5 5 3 1 7 3 3 7 3 5 7 4 1 4 4 4 4 4 5 4 ;run;
%macro CC(PL1,PL2,PL3,PL4);
	max(Proc IN (&PL1)) AND max(Proc IN (&PL2))
  %if &PL3>0 %then %do; AND max(Proc IN (&PL3)) %end;
  %if &PL4>0 %then %do; AND max(Proc IN (&PL4)) %end;
%mend CC;

options mPrint mLogic SymbolGen;
proc sql;
	select Pt,
		%CC(1,2 %if DV LT 6 %then %do; 3 %end; )	as CC12_3
	from x
	group by Pt
;
quit;

 

10 REPLIES 10
Haris
Lapis Lazuli | Level 10

Sorry, I can't insert line-breaks for some reason.  The DATA step ignores them 😞

Tom
Super User Tom
Super User

@Haris wrote:

Sorry, I can't insert line-breaks for some reason.  The DATA step ignores them 😞


Always click on the Insert Code (or Insert SAS Code) icon to edit when you are modifying the number of lines in the inserted text.

Tom
Super User Tom
Super User

I cannot understand what you are trying to do.

This code makes no sense:

 %if DV LT 6 %then %do; 3 %end; 

The letter D comes after the digit 6 so you are going to always generate 3 with that code.

 

If you want to test the value of a dataset variable you need to use SAS code, not macro code.

 

Please show the actual SAS code you are trying to use the macro processor to generate.  Then perhaps we can help you generate it (if any code generation is needed).

 

 

Tom
Super User Tom
Super User

Are you just trying to do this?

data x;
  input Pt Proc DV ;
cards;
1 1 6
1 2 6
1 4 6
2 1 5
2 3 5
2 5 5
3 1 7
3 3 7
3 5 7
4 1 4
4 4 4
4 5 4
;

proc sql ;
create table want as
select pt
     , (max(pt=1)
    or max(pt=2)
    or max(pt=3 and DV < 6)
       ) as flag
from x
group by Pt
;
quit;

 

Haris
Lapis Lazuli | Level 10

Thanks for your attention and input, Tom.

 

I realize now that my post contained too much unnecessary detail irrelevant to the question I am asking.  The fact that I renamed variable DV to DataVrsn when trying to fix the line-break issues did not help matters at all.

 

Thanks, for straightening up the fact that you CANNOT use variable values in the %IF %THEN conditional processing.  Not the way I am trying to go about it anyway.  But, in the end, that's what I am trying to accomplish: change a list that is evaluated by the <VarName> IN (Value1, ..., ValueN) statement conditional on the value of the DataVrsn variable.  Hope this code will illustrate it better: what I need is variable CC123.  What I am hoping to do is to eliminate redundant typing of both redundant THEN and ELSE conditions and replace them with a conditional processing that adds a value to the list.

%macro runSQL();
proc sql;
	select Pt, Proc, DataVrsn,
	   case when DataVrsn<6 then max(Proc IN (1)) AND max(Proc IN (2  ))
	   						else max(Proc IN (1)) AND max(Proc IN (2 3)) end 		AS CC123,
		max(Proc IN (1)) AND max(Proc IN (2 %if DataVrsn LT 6 %then %do; 3 %end; )) AS ConditionalCC123
	from x
	group by Pt
	order by Pt, Proc
;
quit;
%mend runSQL;

%runSQL;
Tom
Super User Tom
Super User

Why? What will it gain you?

Not sure I see any advantage in making the code harder to understand.

Tom
Super User Tom
Super User

If you want to use the macro language to generate SAS code it is best to start with working SAS code.

So perhaps can start with this code, which produces your requested results for the example input.

 

proc sql ;
create table want as
select pt
     , (max(pt=1)
    or max(pt=2)
    or max(pt=3 and DV < 6)
       ) as flag
from x
group by Pt
;
quit;

Now decide which part of that code you need to change.  Is it the list of values?  Then change the code to use macro variables and set the macro variables to values.

 

 

%let list1=1;
%let list2=2;
%let list3=3;
proc sql ;
create table want as
select pt
     , (max(pt in (&list1))
    or max(pt in (&list2))
    or max(pt in (&list3) and DV < 6)
       ) as flag
from x
group by Pt
;
quit;

Now you can change the values of the macro variables and see if it works as expected.

%let list1=11 23 45;
%let list2=22 44;
%let list3=13 56;

Once you get that working wrap it in a macro definition using those macro variable names as the parameters.

 

Haris
Lapis Lazuli | Level 10

Thanks, Tom.  Appreciate your continued effort to help me with this.  

 

As to the WHY?  I have (sometimes long) lists of codes that vary usually by one code.   As I explained in the original post, I am trying to avoid re-typing these lists.  Say I have 15 codes for DV=6 and those same 15 plus one more for DV=5.  I'm trying to add that one code conditionally on the value of DV without the need to re-type.  The lists are also changing all the time so, when a change happens, I don't want to edit the list in multiple places.

 

I've entertained the idea of using %LET macro variable assignments but there are dozens of these lists many with permutation.  I am afraid that a code with &MacroVariables would become even less readable.

 

Hope that helps you understad the puruit here.  Thanks again.

Tom
Super User Tom
Super User

If you have large lists leave them in DATA, not macro variables.

 

Try this:

data lists;
   infile cards truncover;
   input name :$32. value $100.;
cards;
baselist 2 
lt6dvlist &baselist 4
;

Now you can use that to create macro variables.

data _null_;
  set lists;
  call symputx(name,value);
run;

And if you print the value you see the full list.  

32   %put &=baselist;
BASELIST=2
33   %put &=lt6dvlist;
LT6DVLIST=2 4

But the actual value includes the reference to the other list

34   %put baselist=%superq(baselist);
baselist=2
35   %put lt6dvlist=%superq(lt6dvlist);
lt6dvlist=&baselist 4

You can probably get similar results just in macro code but you will need recreate the macro variable if the referenced macro variable changes.

42   %let lt6dvlist=&baselist 3;
43   %put &lt6dvlist;
2 3
44   %put lt6dvlist=%superq(lt6dvlist);
lt6dvlist=2 3

Also if the list is in dataset you can either use the dataset in your queries.

where pt in (select pt from lists where name='baselist')

Or use the dataset to generate code into a text file.  So code list this

filename code temp;
data _null_;
  set lists;
  file code;
  put ', max(pt in (' list ')) as ' name ;
run;

Will generate lines like this:

, max(pt in (2 )) as baselist
, max(pt in (&baselist 4 )) as lt6dvlist

Which you can use %INCLUDE add to you program.

 

 

Haris
Lapis Lazuli | Level 10

Yes, indeed!  A dataset for various code combination is something we're looking into as well.  The combinations we need to cover are quite extensive!

 

Some times its as simple as CC1 = A & B.  That is, if a patient has A and B the she meets criteria for CC1.  Slightly more complicated CC2 = A & IN (B, C).  Other times all three are required and it's CC3 = A & B & C.  And then you get two but not the third for CC4 = A & B & (NOT C).  And so on, and so on, and so on with about 200 base codes combining every which way two, three, four, ... fifteen at a time.

 

Thank you for your input!

 

sas-innovate-white.png

Our biggest data and AI event of the year.

Don’t miss the livestream kicking off May 7. It’s free. It’s easy. And it’s the best seat in the house.

Join us virtually with our complimentary SAS Innovate Digital Pass. Watch live or on-demand in multiple languages, with translations available to help you get the most out of every session.

 

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.

SAS Training: Just a Click Away

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

Browse our catalog!

Discussion stats
  • 10 replies
  • 962 views
  • 0 likes
  • 2 in conversation