BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
alepage
Barite | Level 11

Hello,

 

Is there a nice way to put the number of numerical variable into a macro variable.

The code below does not seems to work.

 

Data test;

set sashelp.class;

array nums(*) _numeric_;

array chrs(*) _character_;

 

nb_num=dim(nums);

nb_chrs=dim(chrs);

%let nb1=nb_num;

%let nb2=nb_chrs;

run;

%put &nb1;

%put &nb2;

 

1 ACCEPTED SOLUTION

Accepted Solutions
Quentin
Super User

As data_null, said I think DIM() function is what you want.  You don't need to store array dimension in a macro variable. 

 

If you have a 0 obs shell data set, you can copy it's variable information to the PDV via:

if 0 then set shell;

 

When the step compiles, the variables from shell will be created in the PDV (with same attributes as in the shell).  During execution time nothing will be read from shell, because if 0 is always false.

 

Below example shows creating a shell data set, then using that shell and simulating some data via arrays:

 

*Make an 0 obs version of class ;
data emptyclass;
  set sashelp.class ;
  stop ;
run ;

data want ;
  if 0 then set emptyclass ;
  array nums{*} _numeric_ ;
  array chrs{*} _character_ ;

  do k=1 to 100;
    do i=1 to dim(nums);
      nums{i}=5+i;
    end;
    do j=1 to dim(chrs);
      chrs{j}=cat('test',j);
    end ;
    output;
  end;
  stop ;
  drop i j k ;
run ;

Note that sex is $1, so it's value is only 't'. 

The Boston Area SAS Users Group is hosting free webinars!
Next up: Joe Madden & Joseph Henry present Putting Power into the Hands of the Programmer with SAS Viya Workbench on Wednesday Nov 6.
Register now at https://www.basug.org/events.

View solution in original post

15 REPLIES 15
data_null__
Jade | Level 19
Lookup CALL SYMPUTX
alepage
Barite | Level 11

As you propose a solution that I have already tried and did not work, I logged out and tried again. Now it works.

Regards,

 

For the community, here's the final solution:

 

Data test;

set sashelp.class;

array nums(*) _numeric_;

array chrs(*) _character_;

call symputx('nb1',dim(nums),'G');

call symputx('nb2',dim(chrs),'G');

run;

%put &nb1;

%put &nb2;

 

data_null__
Jade | Level 19

You should put a STOP statement at the end of you data step.  You can think about the 18 extra things that happened.

Reeza
Super User

I would recommend a different approach - query the SASHELP or DICTIONARY table. 

 

%let lref=SASHELP;
%let dsn=CARS;

proc sql noprint;
select sum(type='char'), sum(Type='num') into :n_char, :n_num
from sashelp.vcolumn
where libname = upcase("&lref.") and upcase(memname) = upcase("&dsn.");
quit;

%put &n_char;
%put &n_num;

Cases where this will not work: 

1. Data stored on a server

2. When you ahve huge libraries with a lot of data sets it may be slower than you'd like. In that case, I would recommend PROC CONTENTS instead.

 

You should also modify your code slightly, either add the STOP as indicated by @data_null__ or set obs=1 on the data set so that if it's a large data set you're not processing it all. 

 

 

Data test;

set sashelp.class (obs=1);

array nums(*) _numeric_;

array chrs(*) _character_;

call symputx('nb1',dim(nums),'G');

call symputx('nb2',dim(chrs),'G');

STOP;

run;

%put &nb1;

%put &nb2;
Reeza
Super User

Actually...SASHELP.VTABLE already has this information stored...in to variables for every SAS dataset, num_character, num_numeric. 

 

 


%let lref=SASHELP;
%let dsn=CLASS;

proc sql noprint;
select num_character, num_numeric into :n_char, :n_num
from sashelp.vtable
where libname = upcase("&lref.") and upcase(memname) = upcase("&dsn.");
quit;

%put &n_char;
%put &n_num;
alepage
Barite | Level 11

Hello, based on what I would like to do, I like you solution.

In that manner, we obtain an empty data set or a template.

 

But if I want to add data to that empty data set, it doesn't seems to work.

Why?

 

Data test2;

set test;

array nums(&nb1);

array chrs(&nb2) $;

Do _n_=1 to 20;

do i=1 to &nb1;

nums{i}=5;

end;

do j=1 to nb2;

chrs{j}='test';

end;

end;

run;

 

 

Reeza
Super User

@alepage wrote:

Hello, based on what I would like to do, I like you solution.

In that manner, we obtain an empty data set or a template.

 

But if I want to add data to that empty data set, it doesn't seems to work.

Why?

 

Data test2;

set test;

array nums(&nb1);

array chrs(&nb2) $;

Do _n_=1 to 20;

do i=1 to &nb1;

nums{i}=5;

end;

do j=1 to nb2;

chrs{j}='test';

end;

end;

run;

 

 


If TEST doesn't exist and you have no OUTPUT statement then nothing would happen. Otherwise it would create a variable nums1-nums&nb1 and chrs1-chrs&nb2 and set the values to 5 and test. What would you like to happen. _N_ is reset at each line so not sure that's good to use as a counter as  well.

 

You have a typo as well, the nb2 should be &nb2.

 

%let lref=SASHELP;
%let dsn=CLASS;

proc sql noprint;
select num_character, num_numeric into :nb1, :nb2
from sashelp.vtable
where libname = upcase("&lref.") and upcase(memname) = upcase("&dsn.");
quit;

%put &n_char;
%put &n_num;


Data test2;

set &lref..&dsn.;

array nums(&nb1);
array chrs(&nb2) $;


do i=1 to &nb1;
    nums{i}=5;
end;
do j=1 to &nb2;
    chrs{j}='test';
end;


run;

What are you trying to do here?

alepage
Barite | Level 11

It is a good question.

I use a DDL then modify a little bit the code to make sure that SAS EG will understand it.

Then, I execute that code in order to obtain an empty data set with all the variables name and variable length as well. Some variable are characters, others are numeric.

 

I could have as many as 500 variables.  Some are characters variables, some are numeric.  I don't want call the variable by name.  So I though that using array could be a good solution to fill up the dataset with generated data.

 

The tests I have done up to now involve the use of array to declare variable such as  var1-var500 and length to specify the length by statement length $50 $40 ... and so on.  It works very fine.  I was able to generate synthetic data.

 

But now, my challenge is to used a template (empty data set) and I though with the help of array to generate synthetic data but it does seem to work.

 

Here's the code I have tested.  it works if I have at least one observation, but with no observation (the stop statement is added), it does not work.  Is there a way to overcome this difficulty.

 

Data test;

set sashelp.class (obs=1);

array nums(*) _numeric_;

array chrs(*) _character_;

call symputx('nb1',dim(nums),'G');

call symputx('nb2',dim(chrs),'G');

 

/*

stop;

*/

run;

%put &nb1;

%put &nb2;

Data test2;

set test;

array nums(*) _numeric_;

array chrs(*) _character_;

Do k=1 to 100;

do i=1 to &nb1;

nums{i}=5+i;

end;

do j=1 to &nb2;

chrs{j}=cat('test',j);

end;

output;

end;

run;

 

 

 

 

data_null__
Jade | Level 19
Why not just use DIM function in the data step DATA TEST2; ?
alepage
Barite | Level 11

I agree with you.  Dim function does the jobs.

However I was interested to know how to keep this information.

Regards,

Quentin
Super User

As data_null, said I think DIM() function is what you want.  You don't need to store array dimension in a macro variable. 

 

If you have a 0 obs shell data set, you can copy it's variable information to the PDV via:

if 0 then set shell;

 

When the step compiles, the variables from shell will be created in the PDV (with same attributes as in the shell).  During execution time nothing will be read from shell, because if 0 is always false.

 

Below example shows creating a shell data set, then using that shell and simulating some data via arrays:

 

*Make an 0 obs version of class ;
data emptyclass;
  set sashelp.class ;
  stop ;
run ;

data want ;
  if 0 then set emptyclass ;
  array nums{*} _numeric_ ;
  array chrs{*} _character_ ;

  do k=1 to 100;
    do i=1 to dim(nums);
      nums{i}=5+i;
    end;
    do j=1 to dim(chrs);
      chrs{j}=cat('test',j);
    end ;
    output;
  end;
  stop ;
  drop i j k ;
run ;

Note that sex is $1, so it's value is only 't'. 

The Boston Area SAS Users Group is hosting free webinars!
Next up: Joe Madden & Joseph Henry present Putting Power into the Hands of the Programmer with SAS Viya Workbench on Wednesday Nov 6.
Register now at https://www.basug.org/events.
alepage
Barite | Level 11
Thanks a lot for your help. it is very appreciated
data_null__
Jade | Level 19

@Quentin Why do you create EMPTYCLASS when you only refer to it in an unexecuted SET?

Quentin
Super User

@data_null__ I made emptyclass because @alepage wrote in one of his responses:

But now, my challenge is to used a template (empty data set) and I though with the help of array to generate synthetic data but it does seem to work.

Here's the code I have tested.  it works if I have at least one observation, but with no observation (the stop statement is added), it does not work.  Is there a way to overcome this difficulty.

 

So I took that to mean in their real setting there was already a shell data set created from some process (I know not how), and they were not using it correctly.  i.e. OP had it on a set statement with obs=1, which will of course cause the step to stop if there are 0 obs.

 

But agreed, it is not necessary to create a 0 obs data set in order to copy a data structure.

The Boston Area SAS Users Group is hosting free webinars!
Next up: Joe Madden & Joseph Henry present Putting Power into the Hands of the Programmer with SAS Viya Workbench on Wednesday Nov 6.
Register now at https://www.basug.org/events.

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

SAS Enterprise Guide vs. SAS Studio

What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.

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
  • 15 replies
  • 3888 views
  • 1 like
  • 4 in conversation