How to remove format and informat in proc sql - sql

I googled and found that one can specify format in proc sql by
proc sql;
create table t1 as
select var1 length=20 label='mylabel' format=$20. informat=$20.
from db;
quit;
I know I can remove the format and informat by data step, but I want to know how to do it in proc sql.
Thanks!

I don't know how to handle it in SQL but you can use proc datasets instead without having to rewrite the dataset, just working at the metadata level:
proc datasets lib=libname memtype=data;
modify dsname;
attrib _all_ format=;
run;

Related

Is there a way to nest a sql statement in a SAS IF/THEN/DO function?

So I have a SAS job that is scheduled to run and update a table regularly. I'm trying to add a functionality that drops the oldest month from the table when it is updating on the first day of a new month. Right now it looks like this:
PROC sql;
create table DropOldMonth as
select *
from ret.ServiceGFR_Impact;
create table DropOldMonth2 as
select *
from DropOldMonth
where date <> 'Jan 2020';
data _null_;
IF FirstDayofMonth = &todaysDate THEN DO;
proc sql;
drop table ret.ServiceGFR_Impact;
data ret.ServiceGFR_Impact;
set work.DropOldMonth2;
END;
run;
But I get this error:
ERROR 117-185: There was 1 unclosed DO block.
right below the Proc sql statement. I assume it's because there's a proc sql statement before and END statement to the DO function. However I need it to drop that table when that IF condition is true.
You may want to edit it in place instead of dropping it:
data ret.ServiceGFR_Impact;
set ret.ServiceGFR_Impact;
where date <> 'Jan 2020';
run;
make sure you have a backup before running it

Use PROC SQL to create keep list for columns

i need select colums whose names contains string '_fire'. Names can be obtained by statement select
proc sql;
create table x as select _name_
from work.x
where lowcase(_name_) like '%_fire'
;quit;
But i dont know, what to do next? I tried insert this data into variable, but then i get error: Invalid value for the KEEP option.
proc sql noprint;
select _name_
into :names
from work.x
where lowcase(_name_) like '%_fire';
quit;
DATA twowks1 ;
SET work.&tabulka. (KEEP = &names. ) ;
RUN;
can anyone help me? Thx
You're missing the separated by in your PROC SQL query.
However, I only get your error when &Names does not exist, so is there an error with your SQL Query?
*To generate your error;
%symdel names;
DATA twowks1;
SET work.&tabulka. (KEEP=&names.);
RUN;
Here is some that works as you're probably expecting.
*Works as expected;
proc sql noprint;
select _name_ into :names separated by " "
from work.x
where lowcase(_name_) like '%_fire';
quit;
DATA twowks1;
SET work.&tabulka. (KEEP=&names.);
RUN;

How to insert partial source code in SAS?

My data is a SAS Table with 50k rows and 300 columns.
Here I make a little example with only 10 columns. Let's say that 3 colums are refecence and the other are variable columns.
Here is my SAS programm:
PROC SQL;
CREATE TABLE WORK.MATRIX(label="MATRIX with variable columns") AS
SELECT t1.REFERENCE_1,
t1.REFERENCE_2,
t1.REFERENCE_3,
t1.COLUMN_A,
t1.COLUMN_B,
t1.COLUMN_C,
t1.COLUMN_D,
t1.COLUMN_E,
t1.COLUMN_F,
t1.COLUMN_G
-------
Variable souce code which makes operation on these columns
-------
FROM WORK.MY_DATA t1;
QUIT;
I alreary have a SAS code that gives me source code for a given choice of columns. Here is the output of my SAS code:
t1.COLUMN_B,
t1.COLUMN_D,
t1.COLUMN_G,
I can now store this code here „c:\My_columns_choice.txt“.
This is what I would like to have:
PROC SQL;
CREATE TABLE WORK.MATRIX(label="MATRIX with variable columns") AS
SELECT t1.REFERENCE_1,
t1.REFERENCE_2,
t1.REFERENCE_3,
INSERT „c:\My_columns_choice.txt“
INSERT „c:\My_source_code_which_makes_operations.txt“
FROM WORK.MY_DATA t1;
QUIT;
So the question arises as follow, is this possible to insert partial source code in SAS programm through a sort of function like INSERT?
What is the correct syntax?
Many thanks.
Cheers
Mauri
You can use %INCLUDE to include multiple lines of code, but you cannot use that to include parts of a statement. But you can use a macro variable to generate code that could be just part of a statement. For example you could make a macro variable that has a comma separated list of column references.
%let varlist=t1.COLUMN_B,t1.COLUMN_D,t1.COLUMN_G;
Then you can reference the macro variable where you want to insert the text.
PROC SQL;
CREATE TABLE MATRIX(label="MATRIX with variable columns") AS
SELECT t1.REFERENCE_1
, t1.REFERENCE_2
, t1.REFERENCE_3
, &varlist
FROM MY_DATA t1
;
QUIT;
If you want to store this in a file you could either store it in the form or the %LET statement above and then just use %INCLUDE to run it in advance of your SQL statement so that the macro variable exists. Note that your file would then need to include full SAS statements and not just a part of a statement.
Or you could write a DATA step (or other code) to read the text file into the macro variable. The advantage of using a DATA step to read the file is then the file can contain only part of a statement. For example here is a simple data step to read in a one line file and store it in a macro variable.
data _null_;
infile 'column_list.txt' ;
input;
call symputx('VARLIST',_infile_);
run;
proc sql;
... &varlist ...
Use %INCLUDE macro statement. Add SOURCE2 option to obtain a log.
%INCLUDE 'c:\My_source_code_which_makes_operations.txt' / SOURCE2;
EDIT:
%include is NOT a macro statement, so in this special case (proc sql) it doesn't work. Only you can include the whole query, but a part of it is not acceptable.
To solve this problem you can read file using data step and create a macro variable, wich you put in select statement.
Example (only one line in text file):
filename f "/folders/myfolders/class.txt";
data _null_;
infile f dlm='00'x lrecl=32767;
length line $32767;
input line;
call symputx('vars', line);
run;
PROC SQL;
CREATE TABLE class AS
SELECT name,
&vars
FROM sashelp.class;
QUIT;

how to append all tables with their table name in SAS

I'm trying to append all the tables(same structure) in the work library into one data set. But I need to have a new column name which can indicate the table name.
I tried two methods:
macro array and do over:
PROC APPEND BASE=_dupout DATA=dup_&dataset. FORCE;
RUN;
Proc SQL:
PROC SQL;
SELECT MEMNAME, catx('.', libname, MEMNAME) INTO : MEMNAMES SEPARATED BY ' '
from dictionary.tables
where libname='WORK';
quit;
DATA DUP_OUT;
SET &MEMNAMES.;
RUN;
but neither of those I can find a way add a new column (table name). Maybe it is a very simple question? I'm stuck..please help...
Very close, use the INDSNAME option in your SET statement.
DATA DUP_OUT;
SET &MEMNAMES. INDSNAME=SOURCE;
DSET=SOURCE;
RUN;

Update an oracle table with data from another table in SAS

I am trying to run the following piece of code to update table summary from data in click_summ table.
data temp(index=(comp=(card_number package_sk)));
set click_summ(where=(^missing(e_1st_click_dt)));
keep card_number package_sk e_1st_click_dt;
run;
data summary(drop=new_date) ;
set summary;
set temp(rename=(e_1st_click_dt= new_date) in=a) key=comp;
if a then do;
e_1st_click_dt = min(e_1st_click_dt,new_date);
end;
else
_ERROR_ = 0; /*No need for IORC errors*/
run;
This particular piece of code is throwing an error saying:
ERROR: The ORACLE table SUMMARY has been opened for OUTPUT. This table already exists, or there is a name conflict
with an existing object. This table will not be replaced. This engine does not support the REPLACE option.
What is the work around for the same? This question is related to a question I raised earlier (Summerizing a table in SAS)
Just change the table name from summary to something else and try..am not sure whether we can use summary as a table name since proc summary is there...not sure but try and see
As error-message says, you can't replace oracle table in DATA-step. The workaround of it would be:
1) To do all data manipulations in an interim SAS-dataset;
2) Delete all rows in an original Oracle table using PROC SQL ... DELETE ...;
3) Add new data (interim dataset) to empty Oracle table using PROC APPEND.
data temp;
set click_summ(where=(^missing(e_1st_click_dt)));
keep card_number package_sk e_1st_click_dt;
run;
data summary(drop=new_date) ;
modify summary temp(rename=(e_1st_click_dt= new_date) in=a);
by card_number, package_sk;
if a then do;
e_1st_click_dt = min(e_1st_click_dt,new_date);
end;
else
_ERROR_ = 0; /*No need for IORC errors*/
run;
Modify was the key. This will work fine with Oracle tables as well. And pretty fast too.