Issue with proc sql to select large number of files - sas

I am trying to select a large number of files using the proc sql statement below
proc sql;
select cats(libname, ".",memname) into :names separated by " "
from dictionary.tables
where upcase(libname) = "MYLIBNAME";
quit;
but when I write %PUT Data sets: &names; nothing appears in the log file and I get an error saying the macro names is not resolved. Any ideas what is going wrong here?

MYLIBNAME is an invalid libref. Librefs have a maximum of 8 characters. MYLIBNAME is 9 characters so there will be no librefs defined in your SAS session that can match it.
What happens if you try libname = "WORK" or libname = "SASHELP" ? Macro variable names will get populated.
Be careful with libraries containing many thousands of tables. A macro variable can only be 64K-2 characters long.

#Richard answer is perfect. if it is still not working do the following.
try outobs =1, just to check with and without where clause
proc sql outobs= 1;
select cats(libname, ".",memname) into :names separated by " "
from dictionary.tables
where upcase(libname) = "SASHELP";
quit;
%put &names;
use proc contents, followed by concatenation. it will show error in next step, if your macro variable is longer than 65534
PROC CONTENTS DATA=SASHELP._ALL_ out= new(keep=memname libname) noprint; RUN
proc sql;
select cats(libname, ".",memname) into :names separated by " "
from new;

Related

Renaming all variables from a SAS Table

I have two SAS tables which are the same, only the column names aren't the same.
The first table D1 has 80 column names that have the following pattern X1000_a010_b020 and the second table D2 has 80 column names that have the following pattern X_1000_a0010_b0020. Please note that they are not in the same order.
I want to make sure that all the columns from D1 have the same names as in D2. In other words, I want to add the underscore after the X and add a 0 after all the a's and b's.
However I don't how to proceed. I would guess that RegEx would be the go to but I am not familiar with it.
As a structure example, some times ago I was using the following code to replace spaces in a column name with an underscore. I would like to do the same but for the underscore after the X and the 0 after the a's and b's.
%macro rename_vars(table);
%local rename_list sqlobs;
proc sql noprint;
select catx('=',nliteral(name),translate(trim(name),'_',' '))
into :rename_list separated by ' '
from sashelp.vcolumn
where libname=%upcase("%scan(work.&table,-2,.)")
and memname=%upcase("%scan(&table,-1,.)")
and indexc(trim(name),' ')
;
quit;
%if &sqlobs %then %do ;
proc datasets lib=%scan(WORK.&table,-2);
modify %scan(&table,-1);
rename &rename_list;
run;
quit;
%end;
%mend rename_vars;
Your example code seems to show you have a plan for how to implement the renaming so let's just concentrate on generating the OLDNAME <-> NEWNAME pairs. You can generate a list of names in a particular dataset with PROC CONTENTS or querying DICTIONARY.COLUMNS with SQL code (or SASHELP.VCOLUMN with any tool). So let's assume you have a dataset named CONTENTS that contains a variable named NAME. So the goal is to create a new variable, which we can call NEWNAME.
So let's just translate the three transformations you say you need directly into individual actions. You can collapse the steps if you want, but there is no pressing need for efficiency in this operation.
data fixed_names;
set contents;
newname = tranwrd(upcase(name),'_A','_A0');
newname = tranwrd(newname,'_B','_B0');
newname = cats(char(newname,1),'_',substr(newname,2));
keep name newname;
run;
Now you could pull that list into a macro variable. So a space delimited list of old=new pairs is useful for rename.
proc sql noprint;
select catx('=',name,newname) into :renames
from fixed_names
where newname ne upcase(name)
;
quit;
Or if the goal is to literally compare the two datasets you might want to generate one list of old names and a separate list of new names.
select name,newname
into :oldlist separated by ' '
, :newlist separated by ' '
from fixed_names
;
Which you could then use with PROC COMPARE directly without any need to rename any variables.
proc compare data=DS1 compare=DS2 ;
var &oldlist;
with &newlist;
run;

SAS: Variable list contains names with '-' symbol, resulting in error during keep= statement

I have SAS datasets with multiple variables like H9999-999-999-999. However, I need to drop the unnecessary columns and am using a variable list(ParamList) to do that:
proc sql;
select _NAME_ into :ParamList separated by ' '
from uniquePlanList;
quit;
%put ParamList = &ParamList.;
proc sql;
create table test as
select * from out.seq_summ(keep=BPT_Cat &ParamList.);
run;
Because my variables contain '-' symbols I receive the following errors:
ERROR 214-322: Variable name - is not valid.
ERROR 214-322: Variable name 000 is not valid.
ERROR 80-322: Expecting a variable name.
ERROR: Invalid value for the KEEP option.
ERROR: Invalid option name -000.
ERROR: Some options for file OUT.SEQ_SUMM were not processed because of errors or warnings noted above.
I know if I were to list out the variables like this:
(keep=BPT_Cat 'H9999-999-999-999'n 'H9999-999-999-998'n)
Then the code would work. But I have some datasets with hundreds of variables. Is there a better way to drop the unnecessary columns than using a variable list? Or is there some clever way to read in the variable list as a string?
I tried using this:
(keep=BPT_Cat %str(&ParamList.)) but that gave me the same errors as above.
Use the NLITERAL() function to generate names in a form that you can use in code.
proc sql noprint;
select nliteral(_NAME_)
into :ParamList separated by ' '
from uniquePlanList
;
quit;
how about:
proc sql;
select quote(_NAME_)||"n" into :ParamList separated by ' '
from uniquePlanList;
quit;
%put ParamList = &ParamList.;
proc sql;
create table test as
select * from out.seq_summ(keep=BPT_Cat &ParamList.);
run;
Don't have SAS with me at the moment can't really test it.

join tables from a library

hi am trying to append the data-sets from a library which contain a specific column variable in them.for example i want to append those data-sets which contain the name column in them from myfile library.
below is my sample code--->
libname myfile'\c:data';
proc sql noprint ;
select distinct catx(".",libname,memname) into :DataList separated by " "
from dictionary.columns
where libname = upcase(myfile) and upcase(name);
quit;
Assuming that the type of the variable is consistent across all datasets something as simple as SET will work:
Data want;
Set &datalist;
Run;

Reading a list of name to a SAS Macro

I am trying to read a list of values into a macro, so that the macro variable would contain the table name and create a column that would contain the table name.
My attempt, which is wrong, was trying to use the code below, and erroring out because of the line " '&tbl' as Table_Dt ". The code below is inefficient, so feel free to enhance it. Thanks for your help.
%macro flat(tbl);
proc sql exec feedback stimer noprint outobs=5;
CREATE TABLE &tbl as
SELECT
ID,
DOB,
'&tbl' as Table_Dt
FROM &tbl..flat_file;
QUIT;
%mend flat;
%flat(flat0113);
%flat(flat0213);
...
%flat(flat1213);
As you are basically processing a list, this could also be done using call execute. No need to write all the information to macro variables. All tables/libraries are already stored in the sashelp tables and therefore are ready for list processing.
data _null_;
set sashelp.vslib (where=(substr(libname,1,4) = 'FLAT')) end =eof;
if _n_ = 1 then call execute ('proc sql exec feedback stimer noprint outobs=5;');
call execute ('
CREATE TABLE '|| libname ||' AS
SELECT ID,
DOB,
"'||compress(libname)||'" as Table_Dt
FROM '||compress(libname)||'.flat_file
;
');
if eof then call execute ('QUIT;');
run;
Macros in quotation marks will only resolve with double quotes, not single. If you want to do a more efficient way, you can do so with the following modified code. I am assuming that you are reading from libraries named flat0113, flat0213, etc.
Step 1: Get a list of all the libnames with the word "flat" in it
proc sql noprint;
select distinct libname
, count(libname)
into: tbl_list separated by ' '
, total_tbls
from sashelp.vmember
where libname LIKE 'FLAT%'
;
quit;
This will create two macro variables: &tbl_list, and &total_tbls.
&tbl_list holds the values flat0113 flat0213 flat ... flat1213.
&total_tbls holds the total number of values in &tbl_list.
Step 2: Loop through the newly created list
%macro readTables;
%do i = 1 %to &total_tbls;
%let tbl = %scan(tbl_list, &i);
proc sql exec feedback stimer noprint outobs=5;
CREATE TABLE &tbl as
SELECT
ID,
DOB,
"&tbl" as Table_Dt
FROM &tbl..flat_file;
quit;
%end;
%mend;
%readTables;
This will read each individual value from &tbl_list one by one until the very end of the list.

macro to transpose and add a prefix after ordering columns' names

I need to run a macro that does a transpose for many variables (and creates a table for each one), orders the columns names, which are numeric, but also adds as a prefix the variable's name (which is a string).
I have a macro in SAS to perform a transpose with different variables as var in the transpose. The code is:
%macro transponer(var);
proc transpose data=labo2.A_svm_200711_200806
out=labo2.D_tr_&var.0;
var &var;
id mes;
by cid;
run;
/*......more code.....*/
select cats(name, '=', &var, name)
into :prefijolista
separated by ' '
from dictionary.columns
where libname='LABO2' and memname= cats('D_TR_',upcase(&var))
and name like '_20%';
quit;
%put &prefijolista;
%mend;
Since mes is numeric I wanted to order the variable, that's why I didn't introduce the "prefix &var" in the proc transpose but instead I did it after the retain (that was useful to order the columns).
The problem starts when I try to introduce the prefix (after the ordering).
Since one of the variables' name is for example "monto", I get the following error (because it is the var variable in the transpose and it's not a column name in the transposed table):
The following columns were not found in the contributing tables:
monto.
My next step would be:
proc datasets library=labo2;
modify D_tr_&var.0;
rename &prefijolista;
quit;
But I cant do it untill I get the previous one done.
So I don't know how to order the columns after the transpose and also add the prefix.
How can I solve this?
Thanks!
You need to rename the columns using something like PROC DATASETS.
proc datasets lib=work nolist;
modify myDataSet;
rename old_col_name = new_col_name;
run;
quit;
A documentation example is available in the Base SAS guide under the doc for PROC DATASETS. It is available online at: http://support.sas.com/documentation/cdl/en/proc/67327/HTML/default/viewer.htm#n0mfav25learpan1lerk79jsp30n.htm
The problem was that &var inside the cats function inside a macro hast to use
" "
Also you could use
sysfunc(cats(D_TR, &a)
So finally the code will remain like:
%let a = %upcase(&var);
%put &a;
%let b=%sysfunc(cats(D_TR_,&a));
%put &b;
proc sql;
select cats(name, '=', "&var" , name)
into :prefijolista
separated by ' '
from dictionary.columns
where libname='LABO2' and memname= "&b"
and name like '_20%';
quit;
%put &prefijolista;
%put "&b";
PROC datasets library=LABO2;
modify &b;
rename &prefijolista;
quit;
%put "ult" &b;
Not very straightforward, but worked. :)