SAS Programming

DATA Step, Macro, Functions and more
BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
acordes
Rhodochrosite | Level 12

I want to macrotize the following code that works. It doesn't produce an error or log, it just does not terminate. 

 

data public.want;
set public.have;
length batch_id_dt1 batch_id1 varchar(*);



	batch_id_dt1=strip(batch_id_dt);
	drop batch_id_dt;
	rename batch_id_dt1=batch_id_dt;
	
	batch_id1=strip(batch_id);
	drop batch_id;
	rename batch_id1=batch_id;

run;

I'm trying to plug-in the text from a macro function. Here is my failed attempt. 

%macro varcharer(name=);
	&name.1=strip(&name);
	drop &name;
	rename &name.1=&name;
%mend;

data public.want;
set public.have(where=(datepart(timestamp)='28mar2025'd));
length batch_id1 varchar(*);
array temp batch_id;

do i=1 to dim(temp);
/* call execute('%varcharer(name=' ||vnamex(temp(i)) || ');'); */
call execute('%varcharer(name=batch_id);');
end;

run;

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
andreas_lds
Jade | Level 19

This should work:

data public.want;
    set public.have;
    length batch_id_dt1 batch_id1 varchar(*);

    %varcharer(name=batch_id);
    %varcharer(name=batch_id_dt);
run;

You could use proc sql to create a variable containing all the variables that need to be converted, assuming it is named "var_list":

%macro convert();
data public.want;
    set public.have;
    length batch_id_dt1 batch_id1 varchar(*);

    %do i = 1 %to %sysfunc(countw(&var_list, %str( )));
        %let var = %scan(&var_list, &i, %str( ));
        %varcharer(name= &var);
    %end;
run;
%mend convert;
%convert();

Code is untested.

View solution in original post

18 REPLIES 18
PaigeMiller
Diamond | Level 26

You macro resolves to data step code. It cannot run outside of a data step. CALL EXECUTE queues SAS code to run after the data step finishes, and so is incompatible with the macro.

 

In addition, the content of your macro will fail as you can't rename a variable like that.

 

In order to write good macro code, you first (this is MANDATORY not optional) have to write code that works without macros and without macro variables for one case, such as for variable named batch_id. You clearly haven't done that because if you had done this you would know you can't rename variables like this.

 

Finally, I don't see why a macro is needed inside an array in this situation.

 

Here is my solution. Of course this is untested as you haven't provided data for me to work with.

 

data public.want;
set public.have(where=(datepart(timestamp)='28mar2025'd));
array temp batch_id;
do i=1 to dim(temp);
temp(i)=strip(temp(i));
end;
run;

 

So please, next time, you need to do all of these steps

  1. Describe in words the problem you are trying to solve, so we don't have to guess or figure it out ourselves
  2. Show us code that works without macros and without macro variables for at least one iteration (in this case variable named batch_id)
  3. Provide sample data

Do not skip any of these steps

 

 

--
Paige Miller
acordes
Rhodochrosite | Level 12

@PaigeMiller 

My code works without error, now I want to put it with a macro.

PaigeMiller
Diamond | Level 26

Why do you need a macro? I wrote code that does what you want without a macro. Macros seem to be an unnecessary complication.

 

Please state in words what you are trying to do.

--
Paige Miller
acordes
Rhodochrosite | Level 12

@PaigeMiller I can easily have many variables that need conversion from char to varchar format. 

This works:

data public.want;
set public.have;
length batch_id_dt1 batch_id1 varchar(*);



	batch_id_dt1=strip(batch_id_dt);
	drop batch_id_dt;
	rename batch_id_dt1=batch_id_dt;
	
	batch_id1=strip(batch_id);
	drop batch_id;
	rename batch_id1=batch_id;

run;

But for 30 variables I would like to use a macro function. Therefore I've thought about an array for the variables I want to change to varchar. 

And looping over the array elements to plug-in the varnames for the maco function.  

 

PaigeMiller
Diamond | Level 26

@acordes wrote:

@PaigeMiller I can easily have many variables that need conversion from char to varchar format. 


This should have been clearly stated in your original post. We shouldn't have to guess why you are going through these gyrations with CALL EXECUTE and Macros and arrays. Please provide sample data set for us to work with.

 

As far as I can see, the reason you might want VARCHAR is for CAS data sets, this also should have been clearly stated.

 

But I saw the usage of macro functions within data steps and cas actions. And I want to learn it and add it to my tool kit.

 

One of the things you should learn about macros is when NOT to use them. This is such a case. If the code can be easily written without macros, then macros are not necessary. Examples from me and @yabwon show you don't need a macro here.

--
Paige Miller
yabwon
Onyx | Level 15

Listen to @PaigeMiller , there is no need for macro here.

You have a list of variables (batch_id_dt and batch_id) you want to strip leading and trailing spaces, just do it with a loop:

data public.want;
 set public.have(where=(datepart(timestamp)='28mar2025'd));
 array temp batch_id_dt batch_id;
 do over temp;
  temp=strip(temp);
 end;
run;

Bart

 

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



acordes
Rhodochrosite | Level 12

@yabwon I'm not with you. I need to change the batch_id (and x variables more) from char format to varchar format.

I could produce the text with a proc sql select into, no problem, I can do it.

But I saw the usage of macro functions within data steps and cas actions. And I want to learn it and add it to my tool kit. 

 

 

yabwon
Onyx | Level 15

OK, since now it's clear what you want to do, try this:

data public.have;
a=" A";
b="  A";
c="   A";
d="    A";
run;

%macro char2varchar(list);
%local V i;
%let i=1;
%let v = %scan(&list., &i., %str( ));
%do %while (&v. NE );
  length &v.1 varchar(*);
	&v.1=strip(&v.);
	drop &v.;
	rename &v.1=&v.;
  %let i= %eval(&i. + 1);
  %let v = %scan(&list., &i., %str( ));
%end;
%mend char2varchar;

options NOmprint;
options mprint;
data public.want;
  set public.have;

  %char2varchar(A B C D)
run;

[EDIT:]

Just to be clear if "public" is not a CAS library, then conversion to varchar is pointless:

Log:

1    options mprint;
2    data public.want;
3      set public.have;
4
5      %char2varchar(A B C D)
MPRINT(CHAR2VARCHAR):   length A1 varchar(*);
MPRINT(CHAR2VARCHAR):   A1=strip(A);
MPRINT(CHAR2VARCHAR):   drop A;
MPRINT(CHAR2VARCHAR):   rename A1=A;
MPRINT(CHAR2VARCHAR):   length B1 varchar(*);
MPRINT(CHAR2VARCHAR):   B1=strip(B);
MPRINT(CHAR2VARCHAR):   drop B;
MPRINT(CHAR2VARCHAR):   rename B1=B;
MPRINT(CHAR2VARCHAR):   length C1 varchar(*);
MPRINT(CHAR2VARCHAR):   C1=strip(C);
MPRINT(CHAR2VARCHAR):   drop C;
MPRINT(CHAR2VARCHAR):   rename C1=C;
MPRINT(CHAR2VARCHAR):   length D1 varchar(*);
MPRINT(CHAR2VARCHAR):   D1=strip(D);
MPRINT(CHAR2VARCHAR):   drop D;
MPRINT(CHAR2VARCHAR):   rename D1=D;
6    run;

NOTE: VARCHAR data type is not supported by the V9 engine. Variable A has been converted to CHAR data type.
NOTE: VARCHAR data type is not supported by the V9 engine. Variable B has been converted to CHAR data type.
NOTE: VARCHAR data type is not supported by the V9 engine. Variable C has been converted to CHAR data type.
NOTE: VARCHAR data type is not supported by the V9 engine. Variable D has been converted to CHAR data type.
NOTE: There were 1 observations read from the data set PUBLIC.HAVE.
NOTE: The data set PUBLIC.WANT has 1 observations and 4 variables.
NOTE: DATA statement used (Total process time):
      real time           0.04 seconds
      user cpu time       0.03 seconds
      system cpu time     0.03 seconds
      memory              714.18k
      OS Memory           21764.00k

 

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



acordes
Rhodochrosite | Level 12

Thanks Bart, I'll test later. 

And for sure you're right @PaigeMiller to call me on stating well the problem. If I use public as library for me it's always a caslib, but yes, I should have said clearly. 

And to generate test data here in this case I've found it to complicated or time-consuming.  

yabwon
Onyx | Level 15
data public.have;
a=" A";
b="  A";
c="   A";
d="    A";
run;

Not "that" time consuming 😉 🙂

 

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



acordes
Rhodochrosite | Level 12
Ok, too lazy and less resourceful.
andreas_lds
Jade | Level 19

This should work:

data public.want;
    set public.have;
    length batch_id_dt1 batch_id1 varchar(*);

    %varcharer(name=batch_id);
    %varcharer(name=batch_id_dt);
run;

You could use proc sql to create a variable containing all the variables that need to be converted, assuming it is named "var_list":

%macro convert();
data public.want;
    set public.have;
    length batch_id_dt1 batch_id1 varchar(*);

    %do i = 1 %to %sysfunc(countw(&var_list, %str( )));
        %let var = %scan(&var_list, &i, %str( ));
        %varcharer(name= &var);
    %end;
run;
%mend convert;
%convert();

Code is untested.

PaigeMiller
Diamond | Level 26

@andreas_lds 

Why is a macro needed? Why not just an array to do the looping?

--
Paige Miller
acordes
Rhodochrosite | Level 12

Can I use the these lines within an array loop???

 

batch_id_dt1=strip(batch_id_dt);
drop batch_id_dt;
rename batch_id_dt1=batch_id_dt;

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
  • 18 replies
  • 1226 views
  • 4 likes
  • 5 in conversation