Proc SQL : Expecting a name , Case When, End AS - sas

While running the code mentioned below, I'm getting the error "ERROR 22-322: Expecting a name." and the affected code is 'END AS "Z"'. I'm not sure where I'm going wrong with this.
proc sql;
SELECT CASE
WHEN REGION IS NULL THEN ZONE
ELSE REGION
END AS "Z",

SAS didn't recognise the column name as it is not correct syntax. Your options are:
proc sql;
SELECT CASE
WHEN REGION IS NULL THEN ZONE
ELSE REGION
END AS Z /* without quotes */
or
proc sql;
SELECT CASE
WHEN REGION IS NULL THEN ZONE
ELSE REGION
END AS "Z"n /* as name literal */
I suggest the first approach as there is no need to make Z a literal (eg spaces, special chars etc).

Related

DROP TABLE IF EXISTS equivalent for TERADATA from SAS

I'm trying to avoid the error:
ERROR: Teradata execute: Object 'MY_TABLE' does not exist.
When executing TERADATA SQL from SAS
This is the original SAS code I'm using:
proc sql;
connect to TERADATA (user='my_user' password=XXXXXXXXXX MODE=TERADATA TDPID='bdpr');
execute(database MY_DB) by TERADATA;
execute(Drop table MY_TABLE;) by TERADATA;
disconnect from TERADATA;
quit;
According to the documentation the .SET ERRORLEVEL 3807 SEVERITY 0 should fix my problem.
I tried inserting the following before my DROP TABLE statement:
execute(.SET ERRORLEVEL 3807 SEVERITY 0) by TERADATA;
execute(ECHO '.SET ERRORLEVEL 3807 SEVERITY 0') by TERADATA;
I tried combining both:
execute(ECHO '.SET ERRORLEVEL 3807 SEVERITY 0'; Drop table MY_TABLE;) TERADATA;
With either a syntax error for the calls without ECHO or no effect on the error when trying the ECHO variants.
The problem is that the .SET ERRORLEVEL is not a SQL statement but a BTEQ command. According to the docs it should be possible to execute BTEQ commands from standard TERADATA SQL should be possible using the ECHO construct. But from SAS this doesn't seem to be working.
I only need a solution to avoid the SAS error, both SAS side solutions as well as TERADATA solutions are ok for me.
Why not ask Teradata if the table exists and then have SAS conditionally run the drop?
%let tablekind=NONE;
select obj into :tablekind trimmed from connection to teradata
(select case when (tablekind in ('T','O')) then 'TABLE'
else 'VIEW' end as obj
from dbc.tablesv
where databasename = 'MY_DB' and tablename= 'MY_TABLE'
and tablekind in ('V','T','O')
)
;
%if &tablekind ne NONE %then %do;
execute(drop &tablekind. MY_DB.MY_TABLE;) by teradata;
%end;
I don't know the syntax to create an SP from SAS, but I doubt you will have the right to do so.
You might ask your DBA to install following SP, which drops any kind of table (including Volatile).
--Drop a table without failing if the table doesn’t exist:
REPLACE PROCEDURE drop_table_if_exists
(
/* database name, uses default database when NULL.
Must be calling user for Volatile Tables
*/
IN db_name VARCHAR(128) CHARACTER SET Unicode,
/* table name */
IN tbl_name VARCHAR(128) CHARACTER SET Unicode,
OUT msg VARCHAR(400) CHARACTER SET Unicode
) SQL SECURITY INVOKER – check the rights of the calling user
BEGIN
DECLARE full_name VARCHAR(361) CHARACTER SET Unicode;
DECLARE sql_stmt VARCHAR(500) CHARACTER SET Unicode;
DECLARE exit HANDLER FOR SqlException
BEGIN
-- catch "table doesn't exist" error
IF SqlCode = 3807 THEN SET msg = full_name || ' doesn''t exist.';
ELSE
-- fail on any other error, e.g. missing access rights or wrong object tye
RESIGNAL;
END IF;
END;
SET full_name = '"' || Coalesce(db_name,DATABASE) || '"."' || Coalesce(tbl_name,'') || '"';
SET sql_stmt = 'DROP TABLE ' || full_name || ';';
EXECUTE IMMEDIATE sql_stmt;
SET msg = full_name || ' dropped.';
END;
Maybe this could help you, if you run this as a proc call:
replace procedure drop_if_exists( in_object varchar(50))
begin
IF EXISTS(SELECT 1 FROM dbc.tables WHERE tablename = in_object
and databasename='<your database name>') THEN
CALL DBC.SysExecSQL('DROP TABLE ' || in_object);
END IF;
END;
And call this from sas via:
execute (call drop_if_exists(MY_TABLE);) by TERADATA;
EDIT: SAS-invoked procedure creation
proc sql;
connect using DBCONN;
execute(
replace procedure drop_if_exists( in_object varchar(50))
begin
IF EXISTS(SELECT 1 FROM dbc.tables WHERE tablename = in_object
and databasename='<my database>') THEN
CALL DBC.SysExecSQL('DROP TABLE ' || in_object);
END IF;
END;
) by DBCONN;
disconnect from DBCONN;
quit;

Issue with proc sql to select large number of files

I am trying to select a large number of files using the proc sql statement below
proc sql;
select cats(libname, ".",memname) into :names separated by " "
from dictionary.tables
where upcase(libname) = "MYLIBNAME";
quit;
but when I write %PUT Data sets: &names; nothing appears in the log file and I get an error saying the macro names is not resolved. Any ideas what is going wrong here?
MYLIBNAME is an invalid libref. Librefs have a maximum of 8 characters. MYLIBNAME is 9 characters so there will be no librefs defined in your SAS session that can match it.
What happens if you try libname = "WORK" or libname = "SASHELP" ? Macro variable names will get populated.
Be careful with libraries containing many thousands of tables. A macro variable can only be 64K-2 characters long.
#Richard answer is perfect. if it is still not working do the following.
try outobs =1, just to check with and without where clause
proc sql outobs= 1;
select cats(libname, ".",memname) into :names separated by " "
from dictionary.tables
where upcase(libname) = "SASHELP";
quit;
%put &names;
use proc contents, followed by concatenation. it will show error in next step, if your macro variable is longer than 65534
PROC CONTENTS DATA=SASHELP._ALL_ out= new(keep=memname libname) noprint; RUN
proc sql;
select cats(libname, ".",memname) into :names separated by " "
from new;

Length and concat in PROC SQL SAS

I want to define length for some particular columns in select statement and i want to concatenate the two columns i.e sponsor id and sponsor like "ABC-123" in SAS proc sql . Please help
here is the code
proc sql;
select
project_id,
sponsor_id,
empl_country,
region,
empl_dept_descr,
empl_bu_descr,
sponsor,
full_name,
mnth_name FROM Stage0;
quit;
The CATX function will concatenate any number of arguments, of any type, strip the values and place a common delimiter (also stripped) between each. For example:
proc sql;
create table want as
select
catx('-', name, age) as name_age length=20
, catx(':', name, sex, height) as name_gender_height
from sashelp.class;
The length of a new variable will be 200 characters if the variable the CATX result is being assigned to does not have a length specified.
Stripping means the leading and trailing spaces are removed. Arguments that are missing values do not become part of the concatenation.
SAS Documentation for CATX
If you don't know the length you can use a strip() function which will remove leading and trailing spaces, in this case it will remove the spaces generated by the catx() default length:
strip(catx('-', sponsor_id, sponsor))
Code:
proc sql;
select
project_id,
sponsor_id,
empl_country,
region,
empl_dept_descr,
empl_bu_descr,
sponsor,
full_name,
mnth_name ,
/* New column */
strip(catx('-', sponsor_id, sponsor)) as new_id
FROM Stage0;
quit;

special characters in alias Proc sql- SAS 9.3

I need to have a special character (% and space) in the alsias name of a proc sql statement.
proc sql DQUOTE=ANSI;
create table final_data as
select a.column1 as XYZ,
((a.colum2/b.colum2)-1) as "% VS LY"
from table1 a
join table2 b on a.colum3=b.colum3;
quit;
according to the documention, having the option proc sql DQUOTE=ANSI should work..
http://support.sas.com/documentation/cdl/en/acreldb/63647/HTML/default/viewer.htm#a001393333.htm
However, I'm getting this error in SAS 9.3
ERROR: The value % VS LY is not a valid SAS name.
What should I do to make this work?
Thank you so much in advance!
Perhaps a simpler solution would be to use standard naming and a SAS label. If the computed value is between 0 and 1 you can also add a SAS format.
((a.colum2/b.colum2)-1) as vs_ly_pct label='% VS LY' format=percent5.2
If you truly want non-standard column names, you will also need to set
options validvarname = any;
before the Proc SQL.
In SQL an alias is what you use to prefix variable references to tell which input table (or subquery) the variable comes from. Like the a and b in your query. What you are talking about is the variable NAME.
SAS variable names normally are restricted to underscore and alphanumeric characters (and cannot start with a number), but variable LABELS can be any string. You can just specify the label after the name.
select a.column1 as XYZ
, ((a.colum2/b.colum2)-1) as var2 '% VS LY'
Or use the SAS specific LABEL= syntax
select a.column1 as XYZ
, ((a.colum2/b.colum2)-1) as var2 label='% VS LY'

Using date macro variable in PROC SQL

I am having trouble getting a macro variable to work correctly in PROC SQL and it doesn't make sense to me.
First, if I generate a query like this:
PROC SQL;
SELECT
a.*
,'31MAR2016' As EVAL_DATE format=date09.
FROM
myTable a
;
it works as expected and puts a date field at the end of the table.
Then, if I do this:
%Let testDate = '31MAR2016'd;
%put &testDate;
PROC SQL;
SELECT
a.*
,&testDate As EVAL_DATE format=date09.
FROM
myTable a
;
this again runs properly, with the log window showing the value of:
'31MAR2016'd
But, if I do this:
%Let Eval_Date = %sysfunc(intnx (month,%sysfunc(inputn(201603,yymmn6.)) ,0,E),date09.);
%Let Eval_date_test = %str(%')&Eval_Date.%str(%')d;
%Put Eval_date_test;
PROC SQL;
SELECT
a.*
,&Eval_date_test As EVAL_DATE format=date09.
FROM
myTable a
;
SAS stops running with the error;
"ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, a numeric constant, a datetime constant,
a missing value, (, *, +, -, BTRIM, CALCULATED, CASE, EXISTS, INPUT, NOT, PUT, SUBSTRING, TRANSLATE, USER, ^, ~.
ERROR 200-322: The symbol is not recognized and will be ignored."
The log displays the value of &Eval_date_test to be the same '31MAR2016'd as it was in the second example. Note that I created the variable in two steps for clarity, but the same thing happens if you create it in one step.
In case it matters, I am running SAS Enterprise Guide 6.1
Why doesn't this work?
This has to do with how the macro is being dereferenced with the %str() macro. Try the %unquote() macro:
PROC SQL;
SELECT
a.*
, %unquote(&Eval_date_test) As EVAL_DATE format=date09.
FROM
sashelp.cars a
;
quit;
http://support.sas.com/documentation/cdl/en/mcrolref/67912/HTML/default/viewer.htm#p1f5qisx8mv9ygn1dikmgba1lmmu.htm
You are working much too hard and just confusing poor old SAS. Instead of using macro quoting just use the right quote characters to begin with. SAS doesn't care which quote characters you use, but text inside of single quotes is not evaluated for macro triggers and text inside of double quotes is. So '&eval_date'd does not resolve the macro variable reference and "&eval_date"d does.
%let Eval_Date="%sysfunc(intnx(month,%sysfunc(inputn(201603,yymmn6)),0,E),date9)"d;
You're missing a comma after a.*