Connecting to Oracle from SAS - sas

This how I configured my LibName
LIBNAME OrcaleSAS ORACLE USER=UserName PASSWORD=pwd*** PATH = '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=host.unix.####.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=prod.tk.com)))'
And to fetch data below is the code I am using
PROC SQL;
connect using OracleSAS AS OracDB;
select * from connection to oracle
(select * from ENTITY_DATES_WK13);
disconnect from OracDB;
quit;
I am getting the error OracleSAS is not a SAS name & Error in the LIBNAME statement , I am fairly new to SAS..!!

connecting to oracle or any dbms can be done libname or by explicit pass through. Libname method is used to access oracle table(or any dbms) in SAS(tables are usually moved to SAS). Explicit method ( using connect statement) where in query is directly sent to Oracle(or dbms mentioned). This methods are not interchangeable for oracle(or anydbms) table and hence you got error.
below is libname method
LIBNAME OrcaleSAS ORACLE USER=UserName PASSWORD=pwd*** PATH =
'(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=host.unix.####.com)(PORT=1521))
(CONNECT_DATA=(SERVICE_NAME=prod.tk.com)))'
libname sastab "/whatever path/";
proc sql;
create table sastab.tablename as
select *
oratable.tablename
quit;
below is explicit pass through method
proc sql;
connect to oracle as myconn (user=smith password=secret
path='myoracleserver');
create table sastab.newtable as
select *
from connection to myconn
(select *
from oracleschematable);
disconnect from myconn;
quit;

The name you use for your library, called the libref, can only by 8 characters long.
OracleSAS is 9 characters.
Use something shorter.

When you set up a libname you don't need the Connect portion of the PROC SQL. You're mixing two methods of connecting to a SQL database into one.
Assuming your libname worked correctly you can query it the same as you would any other SAS table at this point:
PROC SQL;
create table want as
select * from ENTITY_DATES_WK13;
quit;
proc print data=want(obs=5);
run;
The other method is 'pass through' which means the query is passed fully to the server to run on that side. This means the inside query needs to be Oracle compliant and you can't use SAS functions or data.

At last I ended doing something like this..,
%let usr ="pradeep"
%let pwd ="******"
%let pth = "ORACLEPATH"
%put path: &path;
proc sql;
connect to oracle(user = &usr
password =&pwd
path =&pth buffsize=5000);
/* my code */

Related

Performing T-sql like while loop in Proc sql sas

I have metrics sas table like below
work.met_table
Metrics_Id Metrics_desc
1 Count_Column
2 Sum_Column
3 Eliminate_column
I wanna do something like doing while loop in T-sql
select count(*) :cnt_tbl from work.met_table
%let init_cnt = 1
while (&init_cnt = &cnt_tbl)
begin
select Metrics_desc into :met_nm
from work.met_table
where metrics_id = 1
Insert into some_sas_table
Select * from another table where Metrics_desc =&met_nm
/* Here I wanna loop all values in metrics table one by one */
end
%put &init_cnt = &int_cnt+1;
How this can be done in proc sql? Thanks in advance
If you want to dynamically generate code then use the SAS macro language.
But for your example there is no need to dynamically generate code.
proc sql ;
insert into some_sas_table
select *
from another_table
where Metrics_desc in (select Metrics_desc from work.met_table)
;
quit;
You can also do an explicit pass through. Send your native t-sql code to run on the database Server through SAS rather than bringing the data to the SAS application server to query it.
The example below is explained in details here.
PROC SQL;
CONNECT TO ODBC(DATASRC=SQLdb USER=&SYSUSERID) ;
/* Explicit PASSTHRU with SELECT */
SELECT *
FROM CONNECTION TO ODBC (
SELECT b.idnum o.[SSdatecol] AS mydate
FROM dbo.big_SS_table1 b
LEFT JOIN dbo.other_SStable o
ON b.idnum = o.memberid
WHERE o.otherdatecol >= '2014-10-06'
--This is a T-SQL comment that works inside SQL Server
) ;
;
DISCONNECT FROM ODBC ;
QUIT;

Inserting into DB2 fom SAS dataset with passthrough SQL

I'm still new to SAS and DB2. I have a DB2 Table with a column that stores values encoded as timestamps. I'm trying to load data onto this column from a SAS data set in my Work directory. Some of these timestamps, however, correspond to dates before 01-01-1582 and can not be stored as datetime values in SAS. They are instead stored as strings.
This means that if I want to load these values onto the DB2 table I must first convert them to timestamp with the TIMESTAMP() DB2 function, which, as far as I know, requires passthrough SQL with an execute statement (as opposed to the SAS ACCESS libname method). For instance, in order to write a single value I do the following:
PROC SQL;
connect to db2 (user = xxxx database = xxxx password = xxxx);
execute (insert into xxxx.xxxx (var) values (TIMESTAMP('0001-01-01-00.00.00.000000'))) by db2;
disconnect from db2;
quit;
How can I achieve this for all values in the source data set? A select ... from statement inside the execute command doesn't work because as far as I know I can't reference the SAS Work directory from within the DB2 connection.
Ultimately I could write a macro that executes the PROC SQL block above and call it from within a data step for every observation but I was wondering if there's an easier way to do this. Changing the types of the variables is not an option.
Thanks in advance.
A convoluted way of working around that would be to use call execute:
data _null_;
set sas_table;
call execute("PROC SQL;
connect to db2 (user = xxxx database = xxxx password = xxxx);
execute (
insert into xxxx.xxxx (var)
values (TIMESTAMP('"||strip(dt_string)||"'))
) by db2;
disconnect from db2;
quit;");
run;
Where sas_table is your SAS dataset containing the datetime values stored as strings and in a variable called dt_string.
What happens here is that, for each observation in a dataset, SAS will execute the argument of the execute call routine, each time with the current value of dt_string.
Another method using macros instead of call execute to do essentially the same thing:
%macro insert_timestamp;
%let refid = %sysfunc(open(sas_table));
%let refrc = %sysfunc(fetch(&refid.));
%do %while(not &refrc.);
%let var = %sysfunc(getvarc(&refid.,%sysfunc(varnum(&refid.,dt_string))));
PROC SQL;
connect to db2 (user = xxxx database = xxxx password = xxxx);
execute (insert into xxxx.xxxx (var) values (TIMESTAMP(%str(%')&var.%str(%')))) by db2;
disconnect from db2;
quit;
%let refrc = %sysfunc(fetch(&refid.));
%end;
%let refid = %sysfunc(close(&refid.));
%mend;
%insert_timestamp;
EDIT: I guess you could also load the table as-is in DB2 using SAS/ACCESS and then convert the strings to timestamp with sql pass-through. Something like
libname lib db2 database=xxxx schema=xxxx user=xxxx password=xxxx;
data lib.temp;
set sas_table;
run;
PROC SQL;
connect to db2 (user = xxxx database = xxxx password = xxxx);
execute (create table xxxx.xxxx (var TIMESTAMP)) by db2;
execute (insert into xxxx.xxxx select TIMESTAMP(dt_string) from xxxx.temp) by db2;
execute (drop table xxxx.temp) by db2;
disconnect from db2;
quit;

How to order columns created using Proc SQL in SAS

I am using Proc SQL to create Teradata views. I used Execute (pass through facility) and passed the column names as using variables. But the views which are getting created do not have the columns in the order which was passed into the query. They are getting created at any random order. Is there a way to fix this?
Using the method described here:
data tmp;
aa = 1;
db = 1;
ac = 1;
bb = 1;
run;
proc sql ;
select name into :VARLIST separated by ', '
from dictionary.columns
where libname = 'WORK'
and memname = 'TMP'
order by name ;
quit ;
proc sql ;
create table ordered as
select &VARLIST
from work.tmp ;
quit ;
Not familiar with Teradata per se, more used to working with SAS/DB2, but what if instead of using execute() you would use something like this -- this will create the view on the SAS side (which might not be what you're after, I'm not entirely sure).
proc sql;
connect to teradata (user=testuser password=testpass);
create view work.myView as
select * from connection to teradata
(select var1, var2, var3
from someTable);
quit;

Display SAS to oracle query

I'm using a SAS access to oracle. and I want to see the query that SAS sends to Oracle.
assume that : oracle is the name of the oracle libname and local is the sas libname.
proc sql;
select *
from oracle.oracle_table ot
inner join local.sas_table st
on ot.customer_id = st.customer_id
;
quit;
I want to know if sas retrieves all data from the oracle table and then does the join or it's sending the list of the customer ids.
Thanks !
MK
Use sastrace to see how it's coming over from Oracle, and _method to see how they are being joined.
options sastrace=',,,d' sastraceloc=saslog;
proc sql _method;
select *
from oracle.oracle_table ot
inner join local.sas_table st
on ot.customer_id = st.customer_id
;
quit;

SAS : How to iterate a dataset elements within the proc sql WHERE statement?

I need to create multiple tables using proc sql
proc sql;
/* first city */
create table London as
select * from connection to myDatabase
(select * from mainTable
where city = 'London');
/* second city */
create table Beijing as
select * from connection to myDatabase
(select * from mainTable
where city = 'Beijing');
/* . . the same thing for other cities */
quit;
The names of those cities are in the sas table myCities
How can I embed the data step into proc sql in order to iterate through all cities ?
proc sql noprint;
select quote(city_varname) into :cities separated by ',' from myCities;
quit;
*This step above creates a list as a macro variable to be used with the in() operator below. EDIT: Per Joe's comment, added quote() function so that each city will go into the macro-var list within quotes, for proper referencing by in() operator below.
create table all_cities as
select * from connection to myDatabase
(select * from mainTable
where city in (&cities));
*this step is just the step you provided in your question, slightly modified to use in() with the macro-variable list defined above.
One relatively simple solution to this is to do this entirely in a data step. Assuming you can connect via libname (which if you can connect via connect to you probably can), let's say the libname is mydb. Using a similar construction to Max Power's for the first portion:
proc sql noprint;
select city_varname
into :citylist separated by ' '
from myCities;
select cats('%when(var=',city_varname,')')
into :whenlist separated by ' '
from myCities;
quit;
%macro when(var=);
when "&var." output &var.;
%mend when;
data &citylist.;
set mydb.mainTable;
select(city);
&whenlist.;
otherwise;
end;
run;
If you're using most of the data in mainTable, this probably wouldn't be much slower than doing it database-side, as you're moving all of the data anyway - and likely it would be faster since you only hit the database once.
Even better would be to pull this to one table (like Max shows), but this is a reasonable method if you do need to create multiple tables.
You need to put your proc sql code into a SAS Macro.
Create a macro-variable for City (in my example I called the macro-variable "City").
Execute the macro from a datastep program. Since the Datastep program processes one for each observation, there is no need to create complex logic to iterate.
data mycities;
infile datalines dsd;
input macrocity $ 32.;
datalines;
London
Beijing
Buenos_Aires
;
run;
%macro createtablecity(city=);
proc sql;
/* all cities */
create table &city. as
select * from connection to myDatabase
(select * from mainTable
where city = "&city.");
quit;
%mend;
data _null_;
set mycities;
city = macrocity;
call execute('%createtablecity('||city||')');
run;
Similar to the other solutions here really, maybe a bit simpler... Pull out a distinct list of cities, place into macros, run SQL query within a do loop.
Proc sql noprint;
Select distinct city, count(city) as c
Into :n1-:n999, :c
From connection to mydb
(Select *
From mainTable)
;
Quit;
%macro createTables;
%do a=1 %to &c;
Proc sql;
Create table &&n&a as
Select *
From connection to myDb
(Select *
From mainTable
Where city="&&n&a")
;
Quit;
%end;
%mend createTables;
%createTables;