why I cannot see my datafile on my defining library - sas

I am running the following
%global source_dir util_dir paramf workdir datadir
dataunitid
saserror
;
%let datadir = %str(I:....\KATER\DATA);
%let outdir = %str(I:...\KATER\Results);
I set my library
libname datain "&datadir";
options mstored sasmstore=datain;
and then
%global liste_reg;
%let liste_reg=22 31;
%do k=1 %to %sysfunc(countw(&liste_reg.));
%let reg=%scan(&liste_reg.,&k.);
data hh_record; set datain.hh_record_&reg.; run;
data person_record; set datain.person_record_&reg.; run;
%let outdir_ = &outdir.\output_&reg.;
proc printto log = "&outdir_.Log.txt"; run;
But I get an error:
ERROR: File DATAIN.PERSON_RECORD_.DATA does not exist.
ERROR: File DATAIN.HH_RECORD_.DATA does not exist.
why is this happening, How can I put my data in datain library?
I am new in SAS so i am little confused. In general I realised that there is nothing in both libraries?
EDIT full code:
%global source_dir util_dir paramf workdir datadir
dataunitid
saserror
;
%let source_dir = %str(I:...ONS_Transf_20170523);
*location of code;
%let util_dir = &source_dir.%str(\dsp_utils);
%let datadir = %str(...KATER\DATA);
%let outdir = %str(...\KATER\Results);
%let paramf = &datadir.%str(\parameter_file\param.csv);
options mautosource mrecall sasautos=(sasautos "&source_dir" "&util_dir") nolabel;
%reset_saserror;
libname datain "&datadir";
options mstored sasmstore=datain;
libname outdir "&outdir.\output";
options mstored sasmstore=outdir;
%macro sdc_super_control_KAT;
%global liste_reg;
%let liste_reg=22 31;
%do k=1 %to %sysfunc(countw(&liste_reg.));
%let reg=%scan(&liste_reg.,&k.);
data hh_record;
set datain.hh_record_&reg.;
run;
data person_record;
set datain.person_record_&reg.;
run;
%let outdir_ = &outdir.\output_&reg.;
proc printto log = "&outdir_.Log.txt";
run;
/
%sdc_control;
*copy files to permanent library;
proc copy in=work out=outdir_;
select sdcresults_hh_:;
run;
proc printto;
run;
%end;
data outdir.params;
set diagnostics_params;
run;
%mend sdc_super_control_KAT;
%sdc_super_control_KAT;

I don't think you're showing us the full code. The issue above appears to be due to the &reg macro variable not resolving to a value but there is nothing shown to indicate why that would happen. Also, the error messages are in the wrong order (hh_record_) should come first in the log.
In summary, it's because your reg variable is resolving to a missing value, or because it is not found (if not found, the log should say that though).

Related

SAS - how to not import empty file

I am trying to import all the CSV files in one folder and schedule the program in the SAS management console. Since it has empty CSV files in the folders, it failed to run the code automatically due to the errors. I was wondering if I can skip the steps of importing the empty file in the following codes.
`%macro drive(dir,ext);
%local cnt filrf rc did memcnt name;
%let cnt=0;
%let filrf=mydir;
%let rc=%sysfunc(filename(filrf,&dir));
%let did=%sysfunc(dopen(&filrf));
%if &did ne 0 %then %do;
%let memcnt=%sysfunc(dnum(&did));
%do i=0 %to &memcnt;
%let name=%qscan(%qsysfunc(dread(&did,&i)),-1,.);
%if %qupcase(%qsysfunc(dread(&did,&i))) ne %qupcase(&name) %then %do;
%if %superq(ext) = %superq(name) %then %do;
%let cnt=%eval(&cnt+1);
%put %qsysfunc(dread(&did,&i));
proc import datafile="&dir\%qsysfunc(dread(&did,&i))" out=dsn&cnt
dbms=csv replace;
guessingrows=max;
run;
data dsnnew&cnt (drop=old);set dsn&cnt (rename=(party_id = old)); party_id= input(old,12.);run;
%end;
%end;
%end;
%end;
%else %put &dir cannot be opened.;
%end;
%let rc=%sysfunc(dclose(&did));
%mend drive;`
PROC IMPORT cannot handle CSV files with fewer then 2 lines. You could just count how many lines the file has. No need to count beyond 2.
data _null_;
if eof then call symputx('nobs',_n_-1);
infile "&dir\%qsysfunc(dread(&did,&i))" obs=2 end=eof;
input;
run;
You can then test the value of the NOBS macro variable to decide whether or not to run PROC IMPORT>
%if &nobs>1 %then %do;
....
%end;
If the files all have the same structure then there is no need for the complicated macro code. Instead just read them all with one data step. You will have to write the code, but you will then have full control over how the variables are defined. You could include the actual name of the file as part of the dataset. Or perhaps extract some identifying information from the filename.
data want;
length fname filename $256 ;
infile "&dir/*.csv" filename=fname truncover dsd ;
input #;
* skip the header lines ;
if fname ne lag(fname) then delete;
* save the filename to a permanent variable;
filename=fname;
* Here is where you put the code to actually read the lines ;
input var1 var2 .... ;
run;

Derive unique libref and/or fileref in SAS

I often need to assign (and de-assign) temporary librefs/filerefs as part of utility macros - and thus I need to avoid naming conflicts with any existing librefs/filerefs. I know I could query the sashelp or dictionary tables and use conditional logic to iterate until I find one that isn't assigned, but I wondered if there was some easier way?
For instance, the following will create a uniquely named dataset in the work library:
data;run;
Is there some equivalent for librefs / filerefs?
The FILENAME() function already provides a method for this. When you call it with a missing value for the fileref it generates one using format #LNnnnnn.
6 data test;
7 length fileref $8 ;
8 rc=filename(fileref,,'temp');
9 put rc= fileref=;
10 run;
rc=0 fileref=#LN00056
NOTE: The data set WORK.TEST has 1 observations and 2 variables.
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.01 seconds
11 %global fileref ;
12 %let rc=%sysfunc(filename(fileref,,temp));
13 %put &=rc &=fileref ;
RC=0 FILEREF=#LN00058
The undocumented monotonic function, invoked in the open execution space, is very handy for obtaining an unused value.
libname mylib "C:\temp\sandbox";
data mylib.data%sysfunc(monotonic());
…
run;
Or code a macro to deliver a name for a libref. The macro can also check for existence if so desired:
%macro nextName(lib=,base=data,check=1);
%local index name;
%if %length(&lib) %then %let lib=&lib..;/* handle non-empty lib */
%do %until (&check and not %sysfunc(exist(&name,data)));
%let name = &lib.&base.%sysfunc(monotonic());
%end;
&name
%mend;
data data3;run;
data data4;run;
%put %nextName();
%put %nextName();
%put %nextName();
%put %nextName();
proc sort data=sashelp.class out=%nextname();
by age;
run;
You could go robust macro implementation and test for lib existence and valid check value.
The LIBNAME function has a similar feature as FILENAME but it does not populate the reference name variable as with FILENAME. The only way I can think of would be to compare SASHELP.VLIBNAM before and after. The librefs are in the form WC00000n.
79 data _null_;
80 length libref $32.;
81 libref = ' ';
82 rc = libname(libref,'.');
83 msg = sysmsg();
84 put _all_;
85 run;
libref= rc=-70004 msg=NOTE: Libref refers to the same physical library as WC000004. _ERROR_=0 _N_=1
actually writing one was fairly trivial, and didn't involve querying the (expensive) dictionary table:
libname mcore0 (work);
libname mcore1 (work);
libname mcore2 (work);
%macro mf_getuniquelibref(prefix=mcore,maxtries=1000);
%local x;
%let x=0;
%do x=0 %to &maxtries;
%if %sysfunc(libref(&prefix&x)) ne 0 %then %do;
%put Libref &prefix&x is available!;
&prefix&x
%return;
%end;
%end;
%put unable to find available libref in range &prefix.0-&maxtries;
%mend;
%let libref=%mf_getuniquelibref();
%put &=libref;
which returns;
UPDATE:
I've added macros for both of these to the MacroCore library and they can be utilised as follows:
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/macrocore.sas";
%inc mc;
%let libref=%mf_getuniquelibref();
%let fileref=%mf_getuniquefileref();

SAS Grid Enabling

I have to pull a lot of data and I am trying to grid enable it to run faster. Unfortunately, I am not a SAS coder so I am trying to modify existing code. I keep getting a 'no matching %DO statement for the %END' error in the waitfor all section of the log. I am not even sure this would work otherwise.
Does someone have grid experience to help me out?
%let _sdtm=%sysfunc(datetime());
%macro splitmonths(begmonth=,endmonth=);
%let rc=%sysfunc(grdsvc_enable(_all_,server=SASApp));
options autosignon;
%do imth=&begmonth %to &endmonth;
signon t&imth;
%syslput imth=&imth/remote=t&imth;
rsubmit t&imth wait=no;
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_VW_HOUPOSSW_FACT_&imth AS
SELECT t1.outletfamily,
t1.ppmonth,
t1.itemnumber,
/* Dollars */
(SUM(t1.totalvalue)) FORMAT=DOLLAR20. AS Dollars
FROM HOUPWP7.vw_houpossw_fact t1
WHERE t1.ppmonth = &imth;
GROUP BY t1.outletfamily,
t1.ppmonth,
t1.itemnumber;
QUIT;
endrsubmit;
%end
waitfor _all_
%do imth=&begmonth %to &endmonth;
t&imth
%end;
;
signoff _all_;
data newdata;
set
%do imth=&begmonth %to &endmonth;
newdata&imth
%end;
;
run;
proc datasets lib=work;
%do imth=&begmonth %to &endmonth;
delete newdata&imth;
%end
quit;
%mend splitmonths
%splitmonths (begmonth=541, endmonth=588)
%let _edtm=%sysfunc(datetime());
%let _runtm=%sysfunc(putn(&_edtm - &_sdtm, 12.4));
%put It took &_runtm second to run the program;enter code here
Trying adding semi-colon to end the %end macro statement just before the start of the waitfor statement.
%end;
waitfor _all_

List only the column names of a dataset

I am working on SAS in UNIX env and I want to view only the column name of a dataset. I have tried proc contents and proc print but both of them list a lot of other irrevelant information that I do not want as it fills up my putty screen and the information ultimately is lost.
I also tried to get this thing frm the sas metadata but that is not working either.
I tried :
2? proc sql;
select *
from dictionary.tables
where libname='test' and memname='sweden_elig_file_jul';
quit;
5?
NOTE: No rows were selected.
6?
NOTE: PROCEDURE SQL used (Total process time):
real time 0.27 seconds
cpu time 0.11 seconds
You're using the wrong dictionary table to get column names...
proc sql ;
select name
from dictionary.columns
where memname = 'mydata'
;
quit ;
Or using PROC CONTENTS
proc contents data=mydata out=meta (keep=NAME) ;
run ;
proc print data=meta ; run ;
Here's one I've used before to get a list of columns with a little bit more information, you can add the keep option as in the previous answer. This just demonstrates how to create a connection to the metadata server, in case that is useful to anyone viewing this post.
libname fetchlib meta
library="libraryName" metaserver="metaDataServerAddress"
password="yourPassword" port=1234
repname="yourRepositoryName" user="yourUserName";
proc contents data=fetchlib.YouDataSetName
memtype=DATA
out=outputDataSet
nodetails
noprint;
run;
For a pure macro approach, try the following:
%macro mf_getvarlist(libds
,dlm=%str( )
)/*/STORE SOURCE*/;
/* declare local vars */
%local outvar dsid nvars x rc dlm;
/* open dataset in macro */
%let dsid=%sysfunc(open(&libds));
%if &dsid %then %do;
%let nvars=%sysfunc(attrn(&dsid,NVARS));
%if &nvars>0 %then %do;
/* add first dataset variable to global macro variable */
%let outvar=%sysfunc(varname(&dsid,1));
/* add remaining variables with supplied delimeter */
%do x=2 %to &nvars;
%let outvar=&outvar.&dlm%sysfunc(varname(&dsid,&x));
%end;
%End;
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%put unable to open &libds (rc=&dsid);
%let rc=%sysfunc(close(&dsid));
%end;
&outvar
%mend;
Usage:
%put List of Variables=%mf_getvarlist(sashelp.class);
Returns:
List of Variables=Name Sex Age Height Weight
source: https://github.com/sasjs/core/blob/main/base/mf_getvarlist.sas
proc sql;
select *
from dictionary.tables
where libname="TEST" and memname="SWEDEN_ELIG_FILE_JUL";
quit;

Referencing a remote SAS work library from another session

Ever had a problem with a SAS session, but been unable to close the session due to having critical files in your remote work library (RWORK)??
I certainly have! So how do you access that library from another (new) session?
Here's a macro I wrote to assign a multiple libref to all remote work directories owned by you :
rsubmit ;
%MACRO DOUBLELIB(USER=&SYSUSERID,LIB=double) / des="Assign libname of double for multiple SAS sessions for the same user";
options nosymbolgen nomprint ;
%LET WRK = %SYSFUNC(pathname(work)) ;
%LET WRKDIR = %SYSFUNC(scan(&WRK,-1,/)) ;
%LET SASTEMP = %SYSFUNC(tranwrd(&WRK,&WRKDIR,)) ;
filename mywork pipe "ls -ls &SASTEMP" ;
data zwork ;
infile mywork lrecl=512 recfm=v pad ;
input #1 char $512. ;
if index(upcase(char),upcase("&USER")) and ^index(char,scan("&WRK",-1,'/')) and index(char,'SAS_work');
path = scan(char,-1,' ') ;
n + 1 ;
call symput('PATH'||compress(n),"&SASTEMP"||strip(path)) ;
call symput('PATHN',compress(n)) ;
run ;
%NOBS(zwork) ;
%IF &NOBS > 0 %THEN %DO ;
libname &LIB (
%DO I = 1 %TO &PATHN ;
"&&PATH&I"
%END ;
) access=readonly ;
%END ;
options symbolgen mprint ;
%MEND DOUBLELIB;
%DOUBLELIB(LIB=dblwork) ;
endrsubmit ;
/* Assign local libref to new remote dblwork libref */
libname rdouble slibref=dblwork server=myserver ;
not sure of the ethics of asking a question you know the answer to, but hopefully others will find this useful!
%macro serverpath;
%put NOTE:; %put NOTE-; %put NOTE-;
%put NOTE- libname OldWork "%sysfunc(pathname(RWORK))" server= remote %str(;);
%put NOTE- rsubmit%str(;);
%put NOTE- libname OldWork "%sysfunc(pathname(RWORK))"%str(;);
%mend; %serverpath;
This will put the code you need in the log. The bit you may need to change is the server= option - this should be the name of the environment you have logged onto (not sure how to reference this programmatically - does anyone else know?)
Obviously the original session needs to remain open (to prevent RWORK from being wiped) and the second session needs to be logged onto the same server...
response to Chris J's response - missing macro..
rsubmit ;
%macro nobs(dsn);
%local dsnid rc;
%global nobs;
%let nobs=.;
%* open the data set of interest ;
%let dsnid=%sysfunc(open(&dsn));
%* If the open was successful get the nobs and CLOSE &dsn ;
%if &dsnid %then %do;
%let nobs=%sysfunc(attrn(&dsnid,nlobs));
%let rc =%sysfunc(close(&dsnid));
%end; %else %do;
%put WARNING: Unable to open &dsn - %sysfunc(sysmsg());
%let nobs=0;
%end; %mend nobs;
endrsubmit;