BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Anandkvn
Lapis Lazuli | Level 10
proc sql;
select  count(make) as total 
into:n
from sashelp.cars;
select make
into:make1-:make99%left(&n)
from sashelp.cars;
quit;


%macro cars;
%do i=1 %to &n;
data &&make&i;
set sashelp.cars;
if make="&&make&i";
run;
%end;
%mend;
%cars;

error below

Anandkvn_0-1682999193295.png

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
ballardw
Super User

Since the data set name variable is changed you now need to add another variable that holds the actual value of the variable to do the selection.

 

proc sql noprint;
  select count(distinct make) 
    into :n trimmed
  from sashelp.cars;
  select distinct compress(make,,'kn') 
    into:make1-:make&n
  from sashelp.cars;
  select distinct make 
    into:makevalue1-:makevalue&n
  from sashelp.cars;
quit;

%macro cars();
  %do i=1 %to &n;
    data &&make&i;/*< data set name value*/
      set sashelp.cars;
      if make="&&makevalue&i"; /*<variable value*/
    run;
  %end;
%mend;

View solution in original post

10 REPLIES 10
Tom
Super User Tom
Super User

You cannot use a string like Mercedes-Benz as the name of a dataset.

 

Come up with another way to name your datasets. 

Perhaps just number them and put the value of MAKE into the LABEL of the dataset.

proc freq data=sashelp.cars;
 tables make / out=makes noprint;
run;

filename code temp;
data _null_;
  set makes ;
  make_num +1;
  file code ;
  put 'data make' make_num '(label=' make :$quote. ');'
    / '  set sashelp.cars;'
    / '  where ' make = $quote. ';'
    / 'run;'
  ;
run;

%include code / source2 ;
379 +data make23 (label="Mazda" );
380 +  set sashelp.cars;
381 +  where Make="Mazda" ;
382 +run;

NOTE: There were 11 observations read from the data set SASHELP.CARS.
      WHERE Make='Mazda';
NOTE: The data set WORK.MAKE23 has 11 observations and 15 variables.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


383 +data make24 (label="Mercedes-Benz" );
384 +  set sashelp.cars;
385 +  where Make="Mercedes-Benz" ;
386 +run;

NOTE: There were 26 observations read from the data set SASHELP.CARS.
      WHERE Make='Mercedes-Benz';
NOTE: The data set WORK.MAKE24 has 26 observations and 15 variables.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
Anandkvn
Lapis Lazuli | Level 10

Hi  Tom,

i want output same like below code using cars dataset 

proc sql;
select count(name) as total_obs
into : n
from sashelp.class;
/* select name */
/* into: name1 -:name%left(&n) */
/* from sashelp.class; */
quit;

%macro make_ds;
%do i=1 %to &n ;
data &&name&i ;
set sashelp.class;
if name="&&name&i";
run;
%end;
%mend make_ds;
%make_ds;

Kurt_Bremser
Super User

 Read @Tom 's post again.

You cannot (you know what "cannot" means?) use a string like "Merceces-Benz" as a dataset name. You must come up with a different naming scheme.

Patrick
Opal | Level 21

As others already stated you can't use a dash in a SAS table name even if you treat it as a literal. That's documented here.

Patrick_0-1683005963734.png

Not that it is advisable in real life situations to split a SAS table into many SAS tables by some category but assuming this is just a learning exercise:
You could just remove any character that's not suitable for use as a SAS table name. Code like below should do.

proc sql noprint;
  select count(distinct make) 
    into :n trimmed
  from sashelp.cars;
  select distinct compress(make,,'kn') 
    into:make1-:make&n
  from sashelp.cars;
quit;

%macro cars();
  %do i=1 %to &n;
    data &&make&i;
      set sashelp.cars;
      if make="&&make&i";
    run;
  %end;
%mend;

%cars();

 

 

Anandkvn
Lapis Lazuli | Level 10

Hi Patrick ,

Thanks for your solution but Merdesbenz dataset no observations 

ballardw
Super User

Since the data set name variable is changed you now need to add another variable that holds the actual value of the variable to do the selection.

 

proc sql noprint;
  select count(distinct make) 
    into :n trimmed
  from sashelp.cars;
  select distinct compress(make,,'kn') 
    into:make1-:make&n
  from sashelp.cars;
  select distinct make 
    into:makevalue1-:makevalue&n
  from sashelp.cars;
quit;

%macro cars();
  %do i=1 %to &n;
    data &&make&i;/*< data set name value*/
      set sashelp.cars;
      if make="&&makevalue&i"; /*<variable value*/
    run;
  %end;
%mend;
Tom
Super User Tom
Super User

Or perhaps better is use the same rule in the WHERE clause that subsets the data as that avoids dataset name collisions.

So all of the records for makes like 'X-Y' and 'X/Y' will end up in the same dataset.

data &&make&i;
  set sashelp.cars;
  where compress(make,,'kn')="&&make&i"; 
run;

You might also need to use UPCASE() function in both places to avoid name collisions causes by name like 'FORD' and 'Ford'. 

Patrick
Opal | Level 21

@Anandkvn wrote:

Hi Patrick ,

Thanks for your solution but Merdesbenz dataset no observations 


True. Just add the compress() function also to the if condition. Below will work.

proc sql noprint;
  select count(distinct make) 
    into :n trimmed
  from sashelp.cars;
  select distinct compress(make,,'kn') 
    into:make1-:make&n
  from sashelp.cars;
quit;

%macro cars();
  %do i=1 %to &n;
    data &&make&i;
      set sashelp.cars;
      if compress(make,,'kn')="&&make&i";
    run;
  %end;
%mend;

%cars();

 

Using a hash table would be an alternative and more efficient coding option as it reads the source data only once.

data _null_;
  if _n_=1 then 
    do;
      dcl hash h1(multidata:'y', dataset:'sashelp.cars(obs=0)');
      h1.defineKey('make');
      h1.defineData(all:'y');
      h1.defineDone();
    end;
  set sashelp.cars;
  by make;
  _rc=h1.add();
  if last.make then
    do;
      _rc=h1.output(dataset:cats('work.',compress(make,,'kn')));
      _rc=h1.clear();
    end;
run;

 

Tom
Super User Tom
Super User

I do not like that method of generating zillions of macro variables instead of keeping the data in a dataset ...

 

But if you are going to do it then do it right.  

  • There is no need to run the query twice, proc sql can count.
  • Make a separate set of macro variables to hold the dataset names so you can add rules to insure the dataset names are valid.
%macro split_ds
(indsname  /* Input dataset name */
,splitvar  /* Variable to split on */
);
proc sql noprint;
select distinct
    quote(trim(&splitvar),"'") 
  , compress(&splitvar,,'kn')
  into :name1-
     , :dsn1-
  from &indsname
;
%let n=&sqlobs;
quit;
%do i=1 %to &n;
data &&dsn&i;
  set &indsname;
  if &splitvar=&&name&i;
run;
%end;
%mend split_ds;

options mprint ;
%split_ds(sashelp.cars,make)

 

yabwon
Onyx | Level 15

One more solution for lazy programmers who want SAS to rename their datasets names into correct form:

%let ds=sashelp.cars;
%let var=Make;

data names_list;
  set &ds.(keep=&var.);
run;

proc sort data=names_list nodupkey;
  by &var.;
run;

proc transpose data=names_list out=tmp;
  var &var.;
  Id &var.;
run;

proc transpose data=tmp(drop=_name_) out=tmp(rename=(col1=&var.));
  var _all_;
run;

proc print data=tmp;
run;

data _null_;
  set tmp;
  call execute(cat('data work.',_name_,';'));
  call execute("set &ds.;");
  call execute(cat('where Make ="',&var.,'";'));
  call execute('run;');
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



sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 10 replies
  • 546 views
  • 2 likes
  • 6 in conversation