We currently use the %runquit macro function as detailed here (http://analytics.ncsu.edu/sesug/2010/CC07.Blanchette.pdf). The %runquit macro is shown below. It basically stops running any more SAS code when an error is encounterd, and can be used as a replacement for both the run and quit statements:
%macro runquit;
; run; quit;
%if &syserr %then %abort cancel;
%mend;
Because using the outobs statement in proc sql triggers a system error (even when the nowarn option is specified) it means we are unable to use the %runquit macro when we need to use the outobs= option.
The below example will generate the following warning message:
proc sql noprint outobs=3 /*nowarn*/;
create table tmp as
select age, count(*) as freq
from sashelp.class
group by 1
order by 2 desc
;
%runquit;
WARNING: Statement terminated early due to OUTOBS=3 option.
Thank you SAS for the completely unnecessary warning. The behaviour is obviously expected because I explicitly wrote code to ask for it. I don't see warnings given when we specify inobs= and outobs= on a set statement. Why does proc sql get the special treatment?
Is there any way to disable the warning issues by the outobs= option in proc sql? Alternatively, is there another way to limit the output rows from proc sql that will not generate an error?
Assuming you are okay with the full SQL statement executing, you can get around this with a data step view that contains the obs limitation.
proc sql noprint ;
create table tmp as
select age, count(*) as freq
from sashelp.class
group by 1
order by 2 desc
;
%runquit;
data tmp_fin/view=tmp_fin;
set tmp(obs=3);
%runquit;
Or make the SQL statement a view and use the data step to make the data set.
proc sql noprint ;
create view tmp_view as
select age
, count(*) as freq
from sashelp.class
group by 1
order by 2 desc
;
quit;
data tmp;
set tmp_view(obs=3) ;
run;
This might be one of your options considering I/O is not a huge constraint, here the reset outobs= option with nowarn does the trick but at IOs cost.
proc sql;
create table test as
select * from sashelp.class;
reset outobs=10 nowarn;
create table test1 as
select * from sashelp.class;
quit;
Related
I would like to create a new table with all tables contained within a library and the variables within each of those tables. I know I can use something like the below to get the table name but I cant find much on getting each variable. I have multiple libraries and each has potentially hundreds of tables. Any help really appreciated.
proc sql ;
create table mytables as
select *
from dictionary.tables
where libname IN ('WORK','SPDSWORK',etc)
order by memname ;
quit ;
Just use PROC CONTENTS with the special _ALL_ member name. Use the NOPRINT option to suppress the output and the OUT= option to name the dataset with the contents information.
proc contents data=mylib._all_ noprint out=contents;
run;
Use distionary.columns instead.
proc sql ;
create table mytables as
select *
from dictionary.columns
where libname IN ('SASHELP')
order by memname ;
quit ;
I have a job which at first imports some xlsx files, then connects to multiple DB tables. Based on conditions, the job selects rows to output, and creates an excel file to send on to the final end-user.
Sometimes, that job returns zero rows, which is acceptable; in that case, I would prefer to create an empty excel file with only the variables, but not run the other code (checking/cleaning code).
How can I conditionally execute code only when there are results?
Something like this:
I get 0 rows
If Result = 0 then Go to *"here"*
Else *"just run the code further"*
You have a few useful things that can help you here.
First off, PROC SQL sets a macro variable SQLOBS, which is particularly useful in identifying how many records were returned from the last SQL query it ran.
proc sql;
select * from sashelp.class;
quit;
%put I returned &SQLOBS rows;
You might use this to drive further processing, either with %IF blocks as Tom notes in comments or other methods I will cover below.
You can also check how many rows are in a dataset explicitly, if you prefer a slightly more robust option.
proc sql;
select count(*) into :class_count from sashelp.class;
quit;
%put I returned &class_count rows;
For very large datasets, there are faster options (using the dataset descriptors, dictionary tables, or a few other options), but for most tables this is fine.
Either way, what I would typically do with a program I intended to run in production would be then to drive the rest of the program from macros.
%macro whatIWantToDo(params);
...
do stuff
...
%mend whatIWantToDo;
proc sql;
mySqlStuff;
quit;
%if &sqlobs. gt 0 %then %do;
%whatIWantToDo(params);
%end;
%else %do;
%put Nothing to do;
%end;
Another option is to use call execute; this is appropriate if your data drives the macro parameters. The big advantage of call execute is that it only runs if you have data rows - if you have zero, it won't do anything!
Say you have some datasets to run code on. You could have up to twelve - one per month - but only have them for the current calendar year, so in Jan you have one, Feb you have two, etc. You could do this:
data mydata_jan mydata_feb mydata_mar;
set sashelp.class;
run;
%macro printit(data=);
title "Printing &data.";
proc print data=&data;
run;
title;
%mend printit;
data _null_;
set sashelp.vtable;
where upcase(memname) like 'MYDATA_%' and nobs gt 0;
callstr = cats('%printit(data=',memname,')');
call execute(Callstr);
run;
First I make the datasets, with a name I can programmatically identify. Then I make the macro that I want to run on each (this could be checking, cleaning, whatever). Then I use sashelp.vtable which shows which tables are created, and check the nobs variable (number of observations) is more than zero. Then I use call execute to run the macro on that dataset!
On the SAS server we have a library that contains thousands of datasets. I want to catalog the contents of a subset of these, all of which have names that begin with "prov". Can I use a wildcard to specify this?
I tried:
PROC CONTENTS DATA=library.prov*;
RUN;
But that just produces a log with this error message:
ERROR: File LIBRARY.PROV.DATA does not exist.
I also tried library.prov%, and that gave the same error.
There are over 100 datasets that start with "prov" so I really don't want to have to do them one at a time. Any ideas?
Depending on what information you want that the CONTENTS procedure produces you could just use the DICTIONARY metadata views.
proc sql ;
create table want as
select *
from dictionary.columns
where libname = 'LIBREF'
and memname like 'PROV%'
;
quit;
Use a WHERE data set option.
proc contents data=sashelp._all_ noprint out=class(where=(memname like 'CLASS%'));
run;
When you specify the keyword _ALL_ in the PROC CONTENTS statement, the step displays a list of all the SAS files that are in the specified SAS library.
Example :
PROC CONTENTS DATA=libref._ALL_ NODS;
RUN;
But to open only the datasets that begin with prov you can use the SQL and add CONTAINS to WHERE e.g:
proc sql ;
create table mytables as
select *
from dictionary.tables
where libname = 'WORK'
order by memname ;
quit ;
Now just run:
PROC CONTENTS DATA mytables;
RUN;
I may be using a different version of SAS check if you have the library SASHELP if so try this based on my note in your comment on the previous response you may see that this works out for you:
proc sql outobs=100;
create table see as
select distinct libname,memname,crdate,modate from sashelp.vtable
where libname='LIBRARY' and memname like 'PROV%'
order by memname;
quit;
I need to perform a procedure on a small set (e.g. 100 rows) of a very big table just to test the syntax and output. I have been running the following code for a while and it's still running. I wonder if it is doing something else. Or what is the right way to do?
Proc sql inobs = 100;
select
Var1,
sum(Var2) as VarSum
from BigTable
Group by
Var1;
Quit;
What you're doing is fine (limiting the maximum number of records taken from any table to 100), but there are a few alternatives. To avoid any execution at all, use the noexec option:
proc sql noexec;
select * from sashelp.class;
quit;
To restrict the obs from a specific dataset, you can use the data set obs option, e.g.
proc sql;
select * from sashelp.class(obs = 5);
quit;
To get a better idea of what SAS is doing behind the scenes in terms of index usage and query planning, use the _method and _tree options (and optionally combine with inobs as above):
proc sql _method _tree inobs = 5;
create table test as select * from sashelp.class
group by sex
having age = max(age);
quit;
These produce quite verbose output which is beyond the scope of this answer to explain fully, but you can easily search for more details if you want.
For further details on debugging SQL in SAS, refer to
http://support.sas.com/documentation/cdl/en/sqlproc/62086/HTML/default/viewer.htm#a001360938.htm
By default it is defined to store macros at WORK.SASMACR.
However at my site location for macros storage is different and I do not know where it is.
Can I find the default macros catalog and view what is inside?
Please see below effects of system options SASMSTORE + MSTORED and STORE option in macro definition on location of the compiled macros - could be something similar was used on your site.
option sasmstore=sasuser mstored;
%macro _mstore /store;
%put This is macro with mstore;
%mend;
%macro _nomstore;
%put This is macro without mstore;
%mend;
proc options option=sasmstore;
run;
Use DICTIONARY.CATALOGS to list macros compiled in your session.
proc sql;
create table macros as
select * from dictionary.catalogs where objtype='MACRO';
quit;
You have three option to find macros `
1.
proc catalog catalog=work.SASMACR;
contents;
run;
2.
proc catalog catalog=work.SASMAC1;
contents;
run;
3.
proc sql;
create table macros as
select * from dictionary.catalogs where objtype='MACRO';
quit;