DATA Step, Macro, Functions and more

Macro with Merge (IN=A)

Accepted Solution Solved
Reply
Frequent Contributor
Posts: 75
Accepted Solution

Macro with Merge (IN=A)

Using SAS EG 7.1.

 

How do I resolve the below? THank you

 

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:

A AND B

 

CODE:

 

%DO YEAR=&FIRSTYR %TO &LASTYR;

 

%do i = 1 %to %sysfunc(countw(&monlist.));

%let month = %sysfunc(putn(%scan(&monlist.,&i.),z2.)); /*i is numeric; whereas &MONTH is char (01,02,etc). So convert numeric i to char &MONTH.*/

PROC SORT DATA =CN; BY ID Date; RUN;

PROC SORT DATA = Tax&YEAR.&MONTH; BY ID Date ; RUN;

DATA TaxCN&YEAR.&MONTH;

MERGE Tax&YEAR.&MONTH(IN=A) CN(IN=B);

BY ID Date;

%IF A AND B %THEN MERGEID='1';%ELSE

%IF A AND NOT B %THEN MERGEID='2';%ELSE

%DO; MERGEID='4';%END;

RUN;

DATA FA&YEAR.&MONTH_CN (drop=MERGEID);

set FA&YEAR.&MONTH_CN;

IF MERGEID='2' Or MERGEID='1';

RUN;

PROC SORT DATA =FACN&YEAR.&MONTH; BY UIN; RUN;

%END;

%END;

 


Accepted Solutions
Solution
‎03-23-2016 04:55 AM
Super User
Posts: 6,928

Re: Macro with Merge (IN=A)

Macro language is used to dynamically create program text; it is dealt with long before a data step is executed.

Also, macro language ONLY knows the datatype character, but not numeric. Special functions need to be used for numeric operations, when necessary.

 

In your case,

%IF A AND B %THEN MERGEID='1';%ELSE
%IF A AND NOT B %THEN MERGEID='2';%ELSE
%DO; MERGEID='4';%END;

means that the macro engine, when it encounters the "and" operator, needs boolean values, but the texts "A" and "B" are not numbers. The numeric variables A and B will exist much later (during data step execution), when the macro has long before finished. The macro cannot know them.

If I read your intentions right, you just need to use the correct data step language at this point:

if A and B
then MERGEID = '1';
else if A and not B
then MERGEID = '2';
else MERGEID = '4';
---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers

View solution in original post


All Replies
Solution
‎03-23-2016 04:55 AM
Super User
Posts: 6,928

Re: Macro with Merge (IN=A)

Macro language is used to dynamically create program text; it is dealt with long before a data step is executed.

Also, macro language ONLY knows the datatype character, but not numeric. Special functions need to be used for numeric operations, when necessary.

 

In your case,

%IF A AND B %THEN MERGEID='1';%ELSE
%IF A AND NOT B %THEN MERGEID='2';%ELSE
%DO; MERGEID='4';%END;

means that the macro engine, when it encounters the "and" operator, needs boolean values, but the texts "A" and "B" are not numbers. The numeric variables A and B will exist much later (during data step execution), when the macro has long before finished. The macro cannot know them.

If I read your intentions right, you just need to use the correct data step language at this point:

if A and B
then MERGEID = '1';
else if A and not B
then MERGEID = '2';
else MERGEID = '4';
---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Contributor
Posts: 37

Re: Macro with Merge (IN=A)

Try converting the "i" value into Char by removing trailing blanks. I think that should be the issue and give a try something like below

%do i = 1 %to %sysfunc(trim(left(put((countw(&monlist.)),best.));

Super User
Super User
Posts: 7,392

Re: Macro with Merge (IN=A)

A far simpler methodology, and one which should be on the first page of every learning manual, is data structure.  You are finding that your life is difficult because of one simple fact, you have put "data" into an area which is not designed to hold "data".  Dataset names, column names, these are here for the purpose of making programming simpler and more efficient, they are Not designed to hold "data".  Column labels, and observations are designed to hold data.  

 

The reason I point this out is that by a simple structure change to your data, you can eliminate all that code, and write simple basic efficient and easy to maintain Base SAS code, which will do exactly the same purpose.  Where you have datasets called taxYYYYMM, create one dataset, which has all the data, with columns for YYYY and MM:

data tax201502;
  a=1; output;
run;
data tax201503;
  a=2; output;
run;
data tax;
  set work.tax: indsname=nme;
  year=input(substr(scan(nme,2,"."),4,4),4.);
  month=input(substr(scan(nme,2,"."),8,2),2.);
run;

Now you have one dataset with all your data in one place.  You can manipulate this one dataset using simple basic datasteps, no need for looping or macros or any other complicated code.  And if for some reason you need to split them up again later on, then that again is a simple datastep output routine.  Remember the data structure is there for your benefit.

☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 3 replies
  • 233 views
  • 4 likes
  • 4 in conversation