Insert and update using proc sql simultaneously in SAS - sas

I am importing a file using proc import
proc import datafile="/opt/Export_d.csv" replace
out=work.export_data; run;
THEN I SELECTED 2 VARIABLES FROM EXPORTED TABLE HAVING SOME CONDITION
proc SQL;
create table work.login2
as select ' SURVEY_ID'n, TIME format=datetime20.,' USERNAME'n
from work.export_data
having TIME=max(TIME) and ' USERNAME'="sasdemo";
quit;
then i created a macro for survey_id because i have to update a value with the Survey_id reference in different table shown in below code:
proc SQL;
select max(' SURVEY_ID'n) into: sid from work.login2;
quit;
now if the ID is blank then i don't have to insert anything but if we have survey_id we have update few columns in a table using below code which is not happening.
proc SQL;
case when ' SURVEY_ID'n is not null then update table_name set SAS_TRACKING_CODE="&Trackingcode."
where SURVEY_ID=&sid.
else end;
quit;

The syntax in your proc sql is not valid. At all. case whencan only be used within statemements like select, where, order by.
The following will do your update if SURVEY_ID is not blank:
proc sql;
update table_name
set SAS_TRACKING_CODE="&Trackingcode"
where SURVEY_ID=&sid. and SURVEY_ID is not null
;
quit;
If what you want is to execute the update only when a condition is true, you should use a macro.
EDIT: that macro would look like this:
%macro update;
%if %symexist(sid) and not &sid = %then %do;
proc sql;
update table_name
set SAS_TRACKING_CODE="&Trackingcode"
where SURVEY_ID=&sid.
;
quit;
%end;
%mend;

Related

Using Proc sql to get statiscs for many variables

I want to use Porc sql to create a data set that contains some statistics as min and max for a lots of variables. The code below only returns a data set with min and max for first variable, for the rest of variables min and max are not show in the data set.
proc sql;
CREATE TABLE Lib.VarNum AS
%do i=1 %to &nvars;
select min(%SCAN(&numvar,&i)) as Min%SCAN(&numvar,&i),
max(%SCAN(&numvar,&i)) as Max%SCAN(&numvar,&i)
from &data (keep= _numeric_);
%end;
quit;
Somebody can help me?
using proc means is best way to do this.
proc means data=sashelp.cars noprint;
var _numeric_;
output out=want (drop= _type_ _freq_ )min(_numeric_) =
max(_numeric_) =/autoname;
run;
but if you want to so it by Proc SQL easiest to macrovariables from dictionary.columns and use them in your tables.
/* creating macrovariables using dictionary.columns*/
proc sql noprint;
select 'min('|| trim(name)||') as min_'||name,
'max('|| trim(name)||') as max_'||name
into :min separated by ',' , :max separated by ','
from dictionary.columns
where libname ='SASHELP'
and memname ='CARS'
and upcase(type) ='NUM';
Values of macrovariable can be checkedly and only partially shown
%put &min;
min(MSRP) as min_MSRP,min(Invoice) as min_Invoice,min(EngineSize) as min_EngineSize
use this macro variables in proc sql statement as shown below.
proc sql;
create table want as
select &min, &max from sashelp.cars;

Proc contents in macro VARNUM

I am exporting the SAS contents to excel file and it works good., however the VARNUM option doesnt seem to work and the variables are in alphabetical order in the excel sheet.
here is the loop.
proc sql;
select count(Name) into :NumOfDatasets from Datas;
select Name into :Dataset1-:Dataset%trim(%left(&NumOfDatasets)) from datas;
quit;
%do index = 1 %to &NumOfDatasets;
proc contents data=&ImportLibrary..&&Dataset&index. varnum
out=&ExportLibrary..&&Dataset&index. (keep=name label);run;
proc export data=&ExportLibrary..&&Dataset&index.
outfile="&ExportLocation"
dbms=excelcs replace;
sheet="&&Dataset&index";
run;
%end;
The varnum option on proc contents affects only the report output of the procedure, not the dataset generated with the out= option.
You could just add a proc sort between your contents and export procedures (and move the keep= dataset option from the contents to the export procedure):
proc sql;
select count(Name) into :NumOfDatasets from Datas;
select Name into :Dataset1-:Dataset%trim(%left(&NumOfDatasets)) from datas;
quit;
%do index = 1 %to &NumOfDatasets;
proc contents data=&ImportLibrary..&&Dataset&index.
out=&ExportLibrary..&&Dataset&index.;
run;
proc sort data=&ExportLibrary..&&Dataset&index.;
by varnum;
run;
proc export data=&ExportLibrary..&&Dataset&index.(keep=name label)
outfile="&ExportLocation"
dbms=excelcs
replace;
sheet="&&Dataset&index";
run;
%end;

SAS insert value with proc sql

So I have a rather interesting problem. I am trying to insert a current date in specific formats and styles, but for some reason it seems to fail. I know its not a formatting issue... But idk how to fix it. a data step solution is welcomed as well... Here's what works.
proc sql;
create table work.test
(test_Id char(50), test_Name char(50), cur_Mo char(1), cur_Qtr char(1), entered_Date char(8));
insert into work.test
values('201703','2017 Mar','0','0','24APR17')
values('201704','2017 Apr','0','0','24APR17')
values('201706','2017 Jun','1','0','23JUN17');
quit;
Here's what doesn't:
proc sql;
insert into work.test
values(catx('',put(year(today()),4.),case when month(today())< 10 then catx('','0',put(month(today()),2.)) else put(month(today()),2.)end) ,catx(' ',[put(year(today()),4.),put(today(),monname3.))],'1','0',put(today(),date7.));
quit;
You can use the %SYSFUNC() macro function to call most other SAS function in macro code. So to generate today's date in DATE7 format you could use:
insert into work.test (date)
values("%sysfunc(date(),date7)")
;
The way I'd probably do it is to use a data step to make a dataset that you would insert, and then insert that dataset.
You can use insert into (...) select (...) from (...) syntax in SAS, and the data step is much more flexible as to allowing you to define columns.
For example:
proc sql;
create table class like sashelp.class;
quit;
proc sql;
insert into class
select * from sashelp.class;
quit;
Or you can specify only certain variables:
proc sql;
insert into class (name, age)
select name, age from sashelp.class;
quit;
data to_insert;
name= 'Wilma';
sex = 'F';
age = 29;
height = 61.2;
weight = 95.3;
run;
proc sql;
insert into class
select * from to_insert;
quit;
Just make sure you either explicitly list the variables to insert/select, or you have the order exactly right (it matches up by position if you use * like I do above).

SAS delete table if 0 Observastions

Is there a procedure that will check to see if a table has 0 observations, and if so then delete it? I assumed there could be an easier way besides manually checking and deleting each table. I'm using a loop command and most of the tables I generate with it will have data but several will have 0 observations.
Thanks if anyone can help.
Assuming you don't have any reason not to trust the metadata, you could look at dictionary.tables:
proc sql;
select memname from dictionary.tables
where libname='WORK' and nobs=0;
quit;
So for example you could pull that into a macro variable and delete the tables in a PROC SQL or PROC DATASETS statement.
proc sql;
select memname into :dellist separated by ' ' from dictionary.tables
where libname='WORK' and nobs=0;
quit;
proc datasets nolist;
delete &dellist;
quit;

How do you read multiple specific datasets and append to one big dataset?

How do you read multiple specific datasets and append to one big dataset?
For example I within a library I have 100s of datasets but I only want to append the datasets that have _du1, _du2
The format and column names are the same
My stab of it doesnt work:
PROC SQL NOPRINT;
SELECT memname INTO :tab1-:tab103 FROM sashelp.vtable
where memname like '_DU%';
SELECT count(*) INTO :obs FROM sashelp.vtable
where memname like '_DU%';
QUIT;
%macro rubber;
%do i=1 %to i=&obs;
proc append base=tot_comb data=&&tab&i force;
run;
%end;
%mend;
%rubber;
PROC APPEND may not actually be faster in this case, or at least not faster by enough to justify doing it, than just writing a datastep.
data tot_comb;
set work._DU:; *or your libname;
run;
This will work if you are on SAS 9.2 or later. If you're on 9.1 or earlier, you'll need to do one proc sql step, like
proc sql;
select memname into :namelist separated by ' '
from dictionary.columns
where libname='WORK' /* or your libname */
and memname eqt '_DU';
quit;
*eqt is like starts with;
data tot_comb;
set &namelist;
run;
That only requires one pass to write, and I'm not sure it will be much slower than so many calls to PROC APPEND.
Here is some code that will get you all the data set names from a given library with some characteristics (starts with _DU). You could use the final macro in a variety of ways to append data sets.
Data _DU1;
var="One";
Run;
Data _DU2;
var="Two";
Run;
PROC SQL;
create table main as
SELECT *
FROM DICTIONARY.COLUMNS
WHERE UPCASE(LIBNAME)="WORK" AND
UPCASE(MEMNAME) like '_DU%';
Select memname
into :dsn separated by ' '
from main;
QUIT;
%Put &dsn;
EDIT (according to your comment)
I added some UPCASE statements and used your count macro var for the number of tab macros
Narrowing your where statement should make your code more efficient
Try this (some of the code is untested):
PROC SQL NOPRINT;
SELECT count(*)
INTO :obs
FROM sashelp.vtable
where UPCASE(LIBNAME)="<YOUR LIB IN UPCASE>" AND
upcase(memname) like '_DU%';
%Let obs=&obs;
SELECT memname
INTO :tab1-:tab&obs
FROM sashelp.vtable
where UPCASE(LIBNAME)="<YOUR LIB IN UPCASE>" AND
upcase(memname) like '_DU%';
QUIT;
%macro rubber;
%do i=1 %to &obs;
proc append base=tot_comb data=&&tab&i force; run;
%end;
%mend;
%rubber;