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;
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'.
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;
You should put a STOP statement at the end of you data step. You can think about the 18 extra things that happened.
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;
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;
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;
@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?
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;
I agree with you. Dim function does the jobs.
However I was interested to know how to keep this information.
Regards,
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'.
@Quentin Why do you create EMPTYCLASS when you only refer to it in an unexecuted SET?
@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.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
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.
Select SAS Training centers are offering in-person courses. View upcoming courses for: