PROC SQL throwing error in cast statement at 'as' and alias at 'as' - sas

PROC SQL;
SELECT end_dt-start_dt as EXPOSURE,
(CASE WHEN (EXPOSURE)<0 THEN 0 ELSE CAST(TRUNC((EXPOSURE)/30+0.99) as
INTEGER) END as bucket) FROM TABLE
This statement works fine in SQL but throws an error in proc sql at both 'as'.

CAST is not a valid SAS SQL function. Use the appropriate SAS SQL function, in this case likely INT(), to convert calculation to an integer value.
If you'd like to use your DB SQL you need to use SAS SQL Pass Through which will pass the code directly to your database, but then the entire query must be valid on that database.

SAS has attributes for every field like Length, Format, Informat. They help store, read and read from a data source.
Your PROC SQL would not require a type cast. Instead use FORMAT statement.
PROC SQL; SELECT end_dt-start_dt as EXPOSURE, CASE WHEN (EXPOSURE)<0 THEN 0 ELSE INT(TRUNC((EXPOSURE)/30+0.99)) END as bucket Format 8. FROM TABLE
Not sure or syntax of the whole statement as I couldn't get to test it, although the whole idea holds true.

Related

Is it possible to read RAW data type in SAS?

I am working with SAS and I am using data from an Oracle database via an ODBC connection. There are some fields I require from this database that have data_type = RAW in the Oracle SQL Developer environment.
SAS is reading these in incorrectly and is returning every field as 2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A with Type = Character and Format and Informat = $HEX40.
One thing I tried to do is read it in as a character variable instead, using character formats and informats using the following code, where mylib is the library connected to an Oracle database.
data want;
set mylib.have (obs= 10000);
format raw_data_var char40.;
informat raw_data_var char40.;
run;
This changed the formats to character but it then converted the cells to ********************
I also tried find some SAS documentation on reading binary data, https://documentation.sas.com/?docsetId=lrcon&docsetTarget=p1vu9u7w1ieua7n17973igt2cq3c.htm&docsetVersion=9.4&locale=en
but unfortunately, I could not find something useful to help.
Can someone point me in the right direction to read in a raw data type using a data step or proc sql?
Thank you
You could use Proc SQL with a pass though query that utilizes the Oracle function RAWTOHEX
proc sql;
connect using mylib;
create table want as
select
a,b,c,input(rawhexed,$HEX32000.) as raw16kchars
from
connection to mylib
(
select a,b,c,rawtohex(myraw) as rawhexed
from have /* oracle side reference */
)
;
quit;

ERROR: Expression using IN has components that are of different data types

I am using the below query in SAS Enterprise Guide to find the count for different offer_ids customers for different dates :
PROC SQL;
CREATE TABLE test1 as
select offer_id,
(Count(DISTINCT (case when date between '2016-11-13' and '2016-12-27' then customer_id else 0 end))) as CUSTID
from test
group by offer_id
;QUIT;
ERROR: Expression using IN has components that are of different data types
Note: Here, Offer_id is the character variable whereas Custome_id is an numeric variable.
Most likely the error is caused by comparing the numeric variable DATE to the character strings '2016-11-13'. If you want to specify a date literal in SAS you must specify the date in DATE9 format and append the letter D after the close quote.
date BETWEEN '13NOV2016'd AND '27DEC2016'd
Note that there is no reference to any external database in the posted code. But even if your source table was tdlib.tdtable instead of work.test you still need to use SAS syntax when writing SAS code. Let the Teradata engine figure out how to convert it for you.
You don't make it clear whether this is being run on SAS or Teradata (via pass through).
I'm guessing SAS, in which case you are missing d after your dates (e.g. '2016-11-13'd). Without this, the dates are being treated as text instead of formatted numbers.
The error statement is slightly misleading, as SAS is treating the between statement as an in statement.

SAS : Select rows from a relationnal database

I work with SAS on a relationnal database that I can access with a libname odbc statement as below :
libname myDBMS odbc datasrc="myDBMS";
Say the database contains a table named 'myTable' with a numeric variable 'var_ex' which values can be 0,1 or . (missing). Now say I want to exclude all rows for which var_ex=1.
If I use the following :
DATA test1;
SET myDBMS.myTable; /* I call directly the table from the DBMS */
where var_ex NE 1;
run;
I don't get rows for which 'var_ex' is missing. Here is a screenshot of the log, with my actual data :
Whereas if I do the exact same thing after importing the table in the Work :
DATA myTable; /* I put myTable in the Work library */
SET myDBMS.myTable;
run;
DATA test2;
SET myTable; /* I call the table from the work */
where var_ex NE 1;
run;
I select rows for which 'var_ex' is 0 or missing, as intended. Here is a screenshot of the log, with my actual data :
The same happens if I use PROC SQL instead of a DATA step, or another NE-like.
I did some research and more or less understood here that unintended stuff like that can happen if you work directly on a DBMS table.
Does that mean is it simply not recommended to work with a DBMS table, and one has to import table locally as below before doing anything ?
DATA myTable; /* I put myTable in the Work library */
SET myDBMS.myTable;
run;
Or is there a proper way to manipulate such tables ?
The best way to test how SAS is translating the data step code into database code is through the sastrace system option. Before running code, try this:
options sastrace=',,,db' sastraceloc=saslog;
Then run your code tests. When you check the log, you will see precisely how SAS is translating the code (if it can at all). If it can't, you'll see,
ACCESS ENGINE: SQL statement was not passed to the DBMS, SAS will do the processing.
followed by a select * from table.
In general, if SAS cannot translate data step code into dbms-specific code, it will pull everything to locally manipulate the data. By viewing this output, you can determine precisely how to get the data step to translate into what you need.
If all else fails, you can use explicit SQL pass-through. The code in parentheses operates the same way as if you're running SQL directly from some other client.
proc sql;
connect to odbc(datasrc='source' user='username' pass='password');
create table want as
select * from connection to odbc
(<code specific to your dbms language>);
disconnect from odbc;
quit;

Rename Variable Name Starting with Number in SAS

I have some results that came from a relational database in a SAS data set. All of the variable names start with numbers, so I can't rename them or access them in a data step. Is there any way to rename them or access them without getting the data out of the RDBMS again?
options validvarname=any; will allow you to access them, and perhaps even use the dataset - you can enclose an "illegal" variable name in "variable name"n (quotes then an n afterwards) to make a name literal which is equivalent to a variable name (like in Oracle using "variable name").
If you want to make them easier to use, you can do something like
proc sql;
select catx(' ','rename',name,'=',cats('_',name,';')) into :renamelist separated by ' '
from dictionary.columns
where libname='WORK' and memname='DATASETNAME'; *perhaps AND ANYDIGIT(substr(name,1,1)) as well;
quit;
proc datasets lib=work;
modify datasetname;
&renamelist;
quit;
You could also try setting options validvarname=v7; before you connect to the RDBMS as it's possible SAS will do this for you (depending on the situation) if you have it set that way (and don't currently).
The answer given by Joe has some helpful information, but I actually discovered that SAS has a (somewhat automatic) method for handling this. When you query data from an RDBMS, SAS will actually replace any column names starting with numbers with an underscore for the first character. So 1994Q4 becomes _994Q4. Thus, you can simply access the data that way.
SAS will, however, preserve the original name from the RDBMS as the variable title, so it will display as 1994Q4 (or whatever) in table view mode.

SAS Proc SQL to add a constant to a variable

I have a SAS dataset with numeric variables to, from, and weight. Some of the observations have value 0 for weight. I need all the weight values to be positive, so I wish to simply add 1 to all weight values.
How can I do that using Proc SQL?
I have tried the following, but it doesn't work:
proc sql;
update mylib.mydata
set weight=weight+1;
quit;
The error is:
ERROR: A CURRENT-OF-CURSOR operation cannot be initiated because
the column "weight" cannot be used to uniquely identify a row
because of its data type.
Also, mylib refers to a Greenplum appliance. This might be the problem...
If you have the database permissions to update that table, you might want to use the SAS/Access pass-through facility. You will need to know the correct syntax for this to work. Here is a non-working example:
proc sql;
connect to greenplm as dbcon
(server=greenplum04 db=sample port=5432 user=gpusr1 password=gppwd1);
execute (
/* Native code goes here */
update sample.mydata
set weight=weight+1
) by dbcon;
quit;
The connection string would be the same as used on the LIBNAME that defined your "mylib' libref.
However, if you are really trying to create a SAS dataset (not update the real table), you can do that with a simple data step:
data mydata;
set mylib.mydata
weight = weight + 1;
run;
That will create a copy of the table that can be used with other SAS procedures.
Check out this note at prosgress.com. You probably need to add UPDATE_MULT_ROWS=YES to your library definition.