BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
odahviing
Fluorite | Level 6

%macro get_num_char(dst,v1,f1) ;
data nc_&dst.;
set &dst.;
length &v1._num 8.;
length &v1._char $20.;
&v1._type = vtype(&v1.);

if &v1._type='N' then do;
&v1._num=&v1.;
&v1._char=strip(put(&v1.,&f1.));
end;
if &v1._type='C' then do;
&v1._char=&v1.;
&v1._num=input(&v1.,&f1.);
end;
run;
%mend get_num_char;

data test;
a1 = '2025-12-05';
a2 = 45996;
run;

%get_num_char(test, a1, yymmdd10.);
%get_num_char(test, a2, yymmdd10.);

 

The first code "%get_num_char(test, a1, yymmdd10.);" log reports an error "The format $YYMMDD was not found or could not be loaded.". Strangely, this error seems to be reported when Macro runs "&v1._char=strip(put(&v1.,&f1.));" when a1 is a character variable rather than a number. I think "if &v1._type='N' then do;" has prevented following code block from running so it shouldn't report an error. Can anyone tell me why this happened?

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

If you don't want the data step compiler to complain about your usage of the wrong type of FORMAT in the PUT() function call then switch to using PUTN() instead so that the checking is done at execution time instead.  Similarly use INPUTN() in your other branch.  This works because PUTN() and INPUTN() (and corresponding character versions) take a character expression as the second argument instead of a format literal.  So the compiler cannot check it since the value is not known until the step runs.

%macro get_num_char(dst,v1,f1) ;
data nc_&dst.;
set &dst.;
length &v1._num 8.;
length &v1._char $20.;
&v1._type = vtype(&v1.);

if &v1._type='N' then do;
&v1._num=&v1.;
&v1._char=strip(putn(&v1.,"&f1."));
end;
if &v1._type='C' then do;
&v1._char=&v1.;
&v1._num=inputn(&v1.,"&f1.");
end;
run;
%mend get_num_char;

Note:  You should also replace STRIP() with LEFT() since you don't really need to remove the trailing spaces since they will just be added back when the value is written into the fixed length character variable.

View solution in original post

7 REPLIES 7
quickbluefish
Barite | Level 11

This is one of the more non-intuitive things about how SAS processes data - I will have to leave this to someone else to explain, but here's a simple example that demonstrates what's going on:

data test;
x=0;
if x=1 then do;
	chk=5/0;
end;
run;

This program will still give a division by zero note in the log even though 'chk' would be missing in this case regardless of whether that was a valid mathematical operation (because x is not equal to 1). 

 

Here's a way around your problem - instead using macro logic to write out the relevant section of the DATA step depending on the var type of <v1>.   ...Well, SAS ODA just ate my example, but essentially, first capture vtype in a separate step:

data _null_;
set &dst;
call symputx("&v1._type", vtype(&v1));
run;

...then use macro logic to write out the relevant portion of the DATA step depending on vtype:

data test2;
set test;
%if &v1._type=N %then %do;
    ** stuff to do when type is N... ;
%end;
%else %do;
    ** stuff to do when type is C... ;
%end;
run;


  

Tom
Super User Tom
Super User

The SAS log for your example explains what is happening.

 71         data test;
 72         x=0;
 73         if x=1 then do;
 74           chk=5/0;
 NOTE: Division by zero detected during the compilation phase, detected at line 74 column 8.
 75         end;
 76         run;

Because 5 and 0 are constants the compiler can check if they will cause trouble before the step starts running.

If you change it to divide by X instead then the compiler will not issue that warning since it cannot know what value X will have.  Even in this case where X has a constant value.

 71         data test;
 72          x=0;
 73          if x=1 then do;
 74           chk=5/x;
 75          end;
 76         run;
 
 NOTE: The data set WORK.TEST has 1 observations and 2 variables.
quickbluefish
Barite | Level 11
Thanks Tom - always learn something from your posts.
Tom
Super User Tom
Super User

If you don't want the data step compiler to complain about your usage of the wrong type of FORMAT in the PUT() function call then switch to using PUTN() instead so that the checking is done at execution time instead.  Similarly use INPUTN() in your other branch.  This works because PUTN() and INPUTN() (and corresponding character versions) take a character expression as the second argument instead of a format literal.  So the compiler cannot check it since the value is not known until the step runs.

%macro get_num_char(dst,v1,f1) ;
data nc_&dst.;
set &dst.;
length &v1._num 8.;
length &v1._char $20.;
&v1._type = vtype(&v1.);

if &v1._type='N' then do;
&v1._num=&v1.;
&v1._char=strip(putn(&v1.,"&f1."));
end;
if &v1._type='C' then do;
&v1._char=&v1.;
&v1._num=inputn(&v1.,"&f1.");
end;
run;
%mend get_num_char;

Note:  You should also replace STRIP() with LEFT() since you don't really need to remove the trailing spaces since they will just be added back when the value is written into the fixed length character variable.

odahviing
Fluorite | Level 6
PUTC and INPUTN indeed work smoothly. However, this just get a new question to me: why format "YYMMDD10." resolves to "$YYMMDD10." when execute PUT in compile phase? Could you please explain this question ?
Tom
Super User Tom
Super User

@odahviing wrote:
PUTC and INPUTN indeed work smoothly. However, this just get a new question to me: why format "YYMMDD10." resolves to "$YYMMDD10." when execute PUT in compile phase? Could you please explain this question ?

SAS is trying to be helpful (and also trying to allow old programs to be run with new versions of SAS).

 

Since you used a CHARACTER variable with the PUT() function you needed to specify a character format.  In the old (very very old) days SAS did not require that character formats start with a $.   When SAS could not find find a character format named YYMMDD it decided you must have meant $YYMMDD. But it could not find that one either so it generated an error message use the "fixed" format name.

odahviing
Fluorite | Level 6

Thanks. An intersting SAS correct mechanism

sas-innovate-2026-white.png



April 27 – 30 | Gaylord Texan | Grapevine, Texas

Registration is open

Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!

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
  • 7 replies
  • 583 views
  • 1 like
  • 3 in conversation