I want to convert the Db2 timestamp into SAS numeric
proc sql;
connect to db2 ;
create table db2ts as
select * from connection to db2
(select char(current timestamp)
from sysibm.sysdummy1)
as db2ts(timestm);
%put &sqlxmsg ;
%put &sqlxrc ;
disconnect from db2;
quit;
data _NULL_;
set DB2TS;
putlog 'timestmb--' timestm;
datets =input(timestm,yymmdd10.);
timets =input(substr(timestm,12),time15.);
dt2=dhms(datets,0,0,timets);
format datets date9. timets time15.6 dt2 datetime26.6;
putlog 'currdatets:' dt2;
call symput('currdatets',catx('-',put(datepart(dt2),yymmdd10.),
translate(put(dt2,tod15.6),'.',':')));
putlog 'currdatets:' currdatets;
run;
timestmb--2022-05-18-16.44.54.587001
currdatets:18MAY2022:16:44:54.587001
%put currdatets: &currdatets;
currdatets: 2022-05-18-16.44.54.587001
Proc sql:
Insert into table1
(Time, Type)
Values
(%sysfunc(quote(&currdatets)), 'A')
Error:
ERROR: Value 1 of VALUES clause 1 does not match the data type of
the corresponding column in the object-item list(in the SELECT clause).
how can I use the macro variable currdatets to insert into the DB2 table?
So your first query is not valid SQL syntax so I am not sure how it even works. Try something like:
create table db2ts as
select * from connection to db2
(select char(current timestamp) as timestmp
from sysibm.sysdummy1)
;
This will create a dataset name db2ts with a character variable named timestmp;
Which should be the similar to what you would get with this data step.
data db2ts ;
timestmp ='2022-05-17-12.02.43.387486';
run;
Now you can convert the string into a DATETIME value by first converting it into a DATE and a TIME value and then combining them.
data want ;
set db2ts;
date=input(timestmp,yymmdd10.);
time=input(substr(timestmp,12),time15.);
datetime=dhms(date,0,0,time);
format date date9. time time15.6 datetime datetime26.6;
put (_all_) (=/);
run;
Results:
timestmp=2022-05-17-12.02.43.387486
date=17MAY2022
time=12:02:43.387486
datetime=17MAY2022:12:02:43.387486
It would be easier if you could figured out if DB2 has a function, or option for the CAST() function, that can let you specify how the string is generated so that it is something that SAS can recognize immediately as a datetime.
Related
I've several SAS (PROC SQL) queries using a MIN(startdate) and MAX(enddate).
To avoid having to calculate these every time I want to do this once at the beginning and store it in a macro variable but I get an error every time.
What is going wrong or how to achieve this ?
Thanks in advance for the help !
This works:
WHERE DATE BETWEEN
(SELECT MIN(startdate format yymmddn8. FROM work.mydata)
AND (SELECT MAX(enddate format yymmddn8. FROM work.mydata)
DATE format is YYMMDD8n and length is 8.
Creating macro variables:
PROC SQL;
SELECT MIN(startdate), MAX(enddate)
INTO :start_date, :end_date
FROM work.mydata
QUIT;
/*Formatting the macro variable:*/
%macro format(value,format);
%if %datatyp(&value)=CHAR
%THEN %SYSFUNC(PUTC(&value, &format));
%ELSE %LEFT(%QSYSFUNC(PUTN($value,&format)));
%MEND format;
Tried:
WHERE DATE BETWEEN "%format(&start_date, yymmddn8.)" AND "%format(&end_date, yymmddn8.)"
Error message:
ERROR: Expression using equals (=) has components that are of different data types
First, you are missing d when providing date for BETWEEN operator.
WHERE DATE BETWEEN "%format(&start_date, yymmddn8.)"d AND "%format(&end_date, yymmddn8.)"d
But keep in mind tht date string must be in date9. format.
"4NOV2022"d
Second, you dont need to format date for this WHERE condition. Date is numeric and numeric value whould work fine.
WHERE DATE BETWEEN &start_date AND &end_date
If you really want to have date formated you can format it directly inside PROC SQL:
PROC SQL;
SELECT
MIN(startdate) format=date9.,
MAX(enddate) format=date9.
INTO
:start_date,
:end_date
FROM
work.mydata
QUIT;
and then
WHERE DATE BETWEEN "&start_date"d AND "&end_date"d
Note that in a PROC SQL query the format attached to a variable does not carry over to the result of aggregate functions, like MIN() and MAX(), performed on the variable. For numeric variables PROC SQL will use the BEST8. format when converting the number into a string to store into the macro variable. You can remove the extra spaces that causes by adding the TRIMMED keyword.
proc sql noprint;
select min(startdate), max(enddate)
into :start_date trimmed
, :end_date trimmed
from work.mydata
;
quit;
Do not add quotes around the values generated by expanding the macro variables. That would generate a string literal and not a numeric literal.
where date between &start_date and &end_date
If you want the values put into the macro variables by the into syntax to be formatted in some other way you need to attach the format as part of the query.
For example if you wanted the value to be something that could be used to generate a date literal, that is a string that the DATE informat understands, then use the DATE format. Make sure the width used is long enough to include all four digits of the year.
proc sql noprint;
select min(startdate) format=date9.
, max(enddate) format=date9.
into :start_date trimmed
, :end_date trimmed
from work.mydata
;
quit;
...
where date between "&start_date"d and "&end_date"d
I've created a user defined format by using proc format statements.Would like to create a macro over it in a way that if the input data changes, the code should able to do change accordingly.
Here is the code:
proc format ;
value $a 1='1-sepstrata'
0='0-Non-sepstrata'
A='A-sepstrata';
run;
In the dateset I've,a columns named stratum which has unique values such as 1,0,A.
Select the distinct values of STRATA and use it to generate the format definition in a file. Then use PROC FORMAT to create the format.
proc sql;
create table fmtdef as
select '$A' as fmtname
, strata as start
, catx('-',strata
,case when (strata='0') then 'Non-sepstrata' else 'sepstrata' end
) as label
from have
group by strata
order by fmtname,start
;
quit;
proc format lib=work.formats cntlin=fmtdef;
run;
I'm having problems to DATEs in SAS Enterprise Guide 7.1 M4.
it's very very simple in SQL Server or VBA but in SAS is driving me crazy.
Problem:
For some strange reason I'm unable to make a simple select. I tried many different forms of formating and convertions but any seems to work
My Simple select returns no observations.
Description of T1.DT_DATE in proc contents
Type: Num
Len: 8
Format: DDMMYY10.
Informat: DATETIME20.
%let DATE_EXAMPLE='01JAN2019'd;
data _null_;
call symput ('CONVERTED_DATE',put(&DATE_EXAMPLE, ddmmyy10.));
run;
%put &CONVERTED_DATE;
PROC SQL;
CREATE TABLE TEST_SELECT AS
SELECT *
FROM MY_SAMPLE_DATA as T1
WHERE T1.DT_DATE = &CONVERTED_DATE
;QUIT;
Intially you are setting up the date properly but you are changing it to a different value that is not understood in where clause. See the resolutions of macrovariable for both macrovariables you have created
%put value of my earlier date value is &DATE_EXAMPLE;
value of my earlier date value is '01JAN2019'd
%put value of my current date value is &CONVERTED_DATE;
value of my current date value is 01/01/2019
change your code to use date literal that is '01JAN2019'd then your code will work. 01/01/2019 value will not make sense in where clause.
PROC SQL;
CREATE TABLE TEST_SELECT AS
SELECT *
FROM MY_SAMPLE_DATA as T1
WHERE T1.DT_DATE = &CONVERTED_DATE
;QUIT;
I'm pulling data from many Teradata tables that have dates stored in MM/DD/YYYY format (ex: 8/21/2003, 10/7/2013). SAS returns them as DDMMMYYYY, or DATE9 format (ex: 21AUG2003, 07OCT2013). Is there a way to force SAS to return date variables as MM/DD/YYYY, or MMDDYY10 format? I know I can manually specify this for specific columns, but I have a macro set up to execute the same query for 65 different tables:
%macro query(x);
proc sql;
connect using dbase;
create table &x. as select * from connection to dbase
(select *
from table.&x.);
disconnect from dbase;
quit;
%mend(query);
%query(bankaccount);
%query(budgetcat);
%query(timeattendance);
Some of these tables will have date variables and some won't. So I'd like the value to be returned as MMDDYY10 format by default. Thanks for your help!
Per the comments to my question, I was able to figure this out using the FMTINFO function. I pretty much used this same code:
proc contents data=mylib._all_ noprint out=contents;
run;
data _null_;
set contents;
where fmtinfo(format,'cat')='date';
by libname memname ;
if first.libname then call execute(catx(' ','proc datasets nolist lib=',libname,';')) ;
if first.memname then call execute(catx(' ','modify',memname,';format',name)) ;
else call execute(' '||trim(name)) ;
if last.memname then call execute(' DDMMYYS10.; run;') ;
if last.libname then call execute('quit;') ;
run;
Found here:
https://communities.sas.com/t5/SAS-Procedures/Change-DATE-formats-to-DDMMYYS10-for-ALL-unknown-number-date/td-p/366637
Consider the following:
data;
format x datetime19.;
x=datetime();
flag='FIRST';
do x=datetime() to x+10 by 1;
output;
flag='';
end;
proc sql noprint;
select x into : test1 from &syslast where flag='FIRST';
select max(x) into: test2 from &syslast;
%put now we see that &test1 is in a different format to &test2;
data _null_; set;
put x=; /* formatted */
call symput('test3',x);
call symput('test4',max(x,sum(x+1000)));
stop;
run;
%put The data step is more consistent - &test3 = &test4;
Seems inconsistent to me. Why does proc sql retain the format in this case? Is this behaviour documented?
There's no way for SAS to know how the result of a function should be formatted. In this case your max() function is simply returning a datetime, but what if there were nested functions or arithmetic inside it. Because of this SAS just treats it as a brand new variable which by default has no format set. If you would like to apply the same format to it you can change your code to this:
select max(x) format=datetime19. into: test2 from &syslast;
In your example, the MAX function creates a new column and when creating new columns, you need to specify all column attributes. So, just add a FORMAT clause to your select statement:
proc sql noprint;
select x into : test1 from &syslast where flag='FIRST';
select max(x) format=datetime19. into: test2 from &syslast;
quit;
%put now we see that &test1 is in a different format to &test2;