How to order columns created using Proc SQL in SAS - 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;

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;

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 */

finding max of many columns using proc sql statement

I am trying to write a PROC SQL query in SAS to determine maximum of many columns starting with a particular letter (say RF*). The existing proc means statement which i have goes like this.
proc means data = input_table nway noprint missing;
var age x y z RF: ST: ;
class a b c;
output out = output_table (drop = _type_ _freq_) max=;
run;
Where the columns RF: refers to all columns starting with RF and likewise for ST. I was wondering if there is something similar in PROC SQL, which i can use?
Thanks!
Dynamic SQL is indeed the way to go with this, if you must use SQL. The good news is that you can do it all in one proc sql call using only one macro variable, e.g.:
proc sql noprint;
select catx(' ','max(',name,') as',name) into :MAX_LIST separated by ','
from dictionary.columns
where libname = 'SASHELP'
and memname = 'CLASS'
and type = 'num'
/*eq: is not available in proc sql in my version of SAS, but we can use substr to match partial variable names*/
and upcase(substr(name,1,1)) in ('A','W') /*Match all numeric vars that have names starting with A or W*/
;
create table want as select SEX, &MAX_LIST
from sashelp.class
group by SEX;
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;

Rearranging variables in a sas dataset- alphabetical order

I have like 500 columns of dataset, and I want to rearrange all the variables in an alphabetical order. How can I do that in any other way than using retain statement before set statement?
You can generate the list of variable names dynamically, and create a new dataset using PROC SQL.
proc sql ;
select name into :VARLIST separated by ', '
from dictionary.columns
where libname = 'SASHELP'
and memname = 'CLASS'
order by name ;
quit ;
proc sql ;
create table ordered as
select &VARLIST
from sashelp.class ;
quit ;