Switch Teradata Accounts - sas

I want to be able to switch between 2 Teradata accounts if the password has expired for one user in SAS.
e.g. connect to teradata (user="&terauser" password="&terapwd" account="&teraacct" server="&tdserver" mode=teradata);
terauser : Password expired
terauser1 : Password valid
Couple of questions:
How do I pre-warn the user to change password. Do I use the DBC.Users table.
How do I swicth accounts, as I will know the status only in the logs.

Proc SQL maintains some automatic macro variables that you can examine:
Proc SQL;
connect to ....;
%put NOTE: SQLXRC=%superq(SQLXRC);
%put NOTE: SQLXMSG=%superq(SQLXMSG);
If you want to automatically test and use the working account you could create a macro that performs try connection and switch account behavior. Be careful about security policies if you put user account info in source code or a plain-text file.
Example:
%macro myConnect ();
%* To be used in the context of a Proc SQL statement;
%* ... assign first account connection parameters to macro variables;
%let terauser=...;
...
%let tdserver = ...;
connect to teradata (user="&terauser" password="&terapwd" account="&teraacct" server="&tdserver" mode=teradata);
%if &SQLXRC eq 0 %then %return;
%* ... assign second account connection parameters to macro variables;
%let terauser=...;
...
%let tdserver = ...;
connect to teradata (user="&terauser" password="&terapwd" account="&teraacct" server="&tdserver" mode=teradata);
%if &SQLXRC eq 0 %then %return;
%put ERROR: Could not connect with current connection parameters;
%abort cancel;
%mend;
Proc SQL can also connect using existing remote library references:
* create remote library references;
libname account1 Teradata ... connection parameters ...;
libname account2 Teradata ... connection parameters ...;
Proc SQL;
connect using account1; * connect using the account1

If you get connected you can ask Teradata when the password was last changed by querying DBC.USERSV. Then if you know what your expiration rules are you can send a message to the user in the SAS log. So if you passwords expire after 120 days your query and report might look like this:
select catx(' ','%put'
, case when (days_left < 2) then 'ERROR:'
when (days_left < 10) then 'WARNING:'
else 'NOTE:'
end
,'Your Teradata password expires in',days_left,'days.')
into :tdpassword_message trimmed
from connection to teradata
(select ((PasswordChgDate+ 120) - date) days_left from dbc.usersV )
;
*----------------------------------------------------------------------------;
* Write message to SAS log ;
*----------------------------------------------------------------------------;
&tdpassword_message;

Related

SAS - Using If-then-do in macro

I'm making a macro to pull tables from a database, then export some of those tables using proc export. I'm doing this by using an if-then-do statement to check if the macro variable equals a string, and if it does then that table gets exported. Here's my code:
%MACRO query(x);
proc sql;
connect using conn;
create table &x. as select * from connection to conn
(select *
from db.&x.);
disconnect from conn;
quit;
%if &x. = "AddressCategory" %then
%do;
proc export data = &x. outfile="C:\path\&x..txt" dbms=dlm replace; delimiter="|";
run;
%end;
%mend query;
%query(AddressCategory);
This produces a dataset named AddressCategory, but the export doesn't work. any ideas? Thanks!
then export some of those tables
Within the macro you likely don't want to check for the item to export by name. If you do, the macro will grow to contain a large number of ifs checking which argument is appropriate for export.
A better macro would have an additional export= parameter that defaults to 0, and the callee sets it to 1 for the data sets to be exported
%MACRO fetcher (
remoteLibref=conn,
remoteSchema=db,
object=,
outlib=work,
out=&object,
export=0,
outpath=C:\exports\&remoteSchema,
outname=&object
);
proc sql;
connect using &remoteLibref;
create table &outlib..&out as select * from connection to &remoteLibref
( select *
from &remoteSchema..&object
);
disconnect from &remoteLibref;
quit;
%if &export %then %do;
proc export
dbms=dlm
data=&outlib..&out.
replace outfile="&outpath.\&object..txt"
;
delimiter="|";
run;
%end;
%mend fetcher;
The invoke it for your various remote objects, specifying explicitly the ones to export
libname conn sqlserver … connection string … ;
%fetcher(object=AddressCategory, export=1)
%fetcher(object=AddressBook)
%fetcher(object=PreferenceCategory, export=1)
%fetcher(object=PreferenceItems)
%fetcher(object=PreferenceProperties)
%fetcher(object=Payouts, export=1)
%fetcher(object=Payouts, RemoteSchema=DBX, export=1, outname=hidden-payouts)

Connecting to Oracle from 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 */

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;

SAS connect to Teradata - Using 2 accounts (switch)

Can someone please help? I have not used SAS in a few years and need some assistance with connecting to Teradata.
I want to connect to Teradata using ACCT1 if the time of day is between 7pm-6:59am or with Acct2 if the time of day is between 7am-6:59pm.
%let
acct1="mismktdev"
acct2="mismktprod"
%include
%macro t_cnnct;
options nomprint;
connect to teradata (tdpid="&tpidxyz" user="&misuid"
password="&mispwd" account="&acct1" mode=teradata);
options mprint;
proc sql;
connect to teradata (user="&terauser" password="&terapwd" mode=teradata);
execute (SET QUERY_BAND = 'Application=PrimeTime;Process=Daily;script=pt_add_history_v30.sas;' for session ) by teradata;
%mend t_cnnct;
proc sql;
Sel * from tblname;
You can use %let timenow=%sysfunc(time(), time.); to get the time at which the program is running and then in you macro do something like :
%macro test();
%let timenow=%sysfunc(time(), time.);
%put &timenow;
%if (&timenow > '19:00'T and &timenow < '06:59'T) %then %do;
/* Your Code for 7pm - 6:59am Here*/
%end;
%else %do;
/*Code for 7am - 6:59pm here*/
%end;
%mend;
%test();
Your idea to use SAS macro variables is just right. Here is a macro to define all the global SAS macro variables you need (including changing the "account" string):
%macro t_cnnct;
%global tdserver terauser terapwd teraacct teradb;
%let tdserver=myTDPID;
%let terauser=myuserID;
%let terapwd=mYTDpassword;
%let teradb=myTDdatabase;
%let now=%sysfunc(time());
%if &now >= %sysfunc(inputn(07:00,time5.))
and &now <= %sysfunc(inputn(19:00,time5.))
%then %let teraacct=mismktdev;
%else %let teraacct=mismktprod;
%mend t_cnnct;
Note the SAS macro variable values are specified without double-quotes! Use double-quotes when they are referenced in your code.
Next, just run the macro before your PROC SQL code to set the variables and use those variables in your connect string:
%t_cnnct;
proc sql;
connect to teradata (user="&terauser" password="&terapwd" account="&teraacct"
server="&tdserver" mode=teradata);
execute (
SET QUERY_BAND = 'Application=PrimeTime;Process=Daily;script=pt_add_history_v30.sas;' for session
) by teradata;
create table mySASds as
select *
from connection to teradata (
select *
from &teradb..tablename
);
quit;
Note that the tdpid= option you were using is an alias for the server= option (which I prefer). Also, the query band you set will remain in effect for the entire PROC SQL run.
And here is an example of a SAS libref that uses the same macro variables:
libname myTD teradata user="&terauser" password="&terapwd" account="&teraacct"
server="&tdserver" database="&teradb" mode=teradata);

Schema was not assigned?

The following code had an error message which I am struggling for trying to figure it out. The error message is: "Libname HDMAPP is not assigned".
Thanks for your help in advance!
%let tmpschema = HDMAPP; *schema for transient tables, test-HDMAPP, prod-HDMAPP;
%let userid = &uid; *data mart user;
%let password = &pw; *data mart password;
%let memschema = HDMTST; *schema for member tables;
%let datasrc = PHEDISRP; *odbc data source to connect to db2;
proc sql;
connect to odbc as HDMconnect (datasrc=&datasrc user=&userid password=&password);
create table &tmpschema..testmp as
select * from connection to HDMconnect
(select * from HDMPRD.MEMBER_CMPL);
disconnect from HDMconnect;
quit;
The error message means that you do not have a SAS library reference ("libref") defined with the name HDMAPP. Because that is the value of your macro variable tmpschema, it's caused by this line in your program:
create table &tmpschema..testmp as
If you are trying to create a SAS data set, you should have a statement like this before the proc sql step:
libname HDMAPP 'path-to-local-file-system';