SAS PROC SQL; - creating DateTime variable - sql

I am trying to create a datetime variable for the past 3 hours... by concatenating DATE variable (in DATE format) and time variable (string hh:mm:ss) within PROC SQL;
Would highly appreciate any help with this!
Example:
APPLCTN_DT = 05NOV2018:00:00:00.000
APPLCTN_TM = 20:04:57
I would like to create a numeric DATETIME field based on the above

Since it looks like your "date" variable is really a DATETIME variable with zero time you perhaps can just add the time part to it?
new_datetime = APPLCTN_DT + input(APPLCTN_TM,time8.);
Or just to be safe you could force the time part of your datetime value to be zero before adding the time part. Here are a couple of ways.
new_datetime = dhms(datepart(APPLCTN_DT),0,0,input(APPLCTN_TM,time8.));
new_datetime = intnx('dtdate',APPLCTN_DT,0) + input(APPLCTN_TM,time8.);

Presuming the _DT variable is actually a datetime value with no exact time portion (thus just the date)).
Use DATEPART to extract SAS date value, INPUT to convert time string to time value, DHMS to construct a target date time value and INTNX to compute a new date time value offset from the target.
data _null_;
APPLCTN_DT = '05NOV2018:00:00:00.000'dt ;
APPLCTN_TM = "20:04:57";
date_part = datepart(applctn_dt);
time_part = input(applctn_tm,time8.);
target_dt = dhms(date_part,0,0,0) + time_part;
target_minus_3hr_dt = intnx ('dthour'
, dhms(date_part,0,0,0) + time_part
, -3
);
target_minus_3hr_exact_dt = intnx ('dtsecond'
, dhms(date_part,0,0,0) + time_part
, -3*60*60
);
format target: datetime20.;
put target_dt ' combined';
put target_minus_3hr_dt ' combined, 3 hours ago';
put target_minus_3hr_exact_dt ' combine, exactly three hours ago (to the second)';
run;
Will show in log
05NOV2018:20:04:57 combined
05NOV2018:17:00:00 combined, 3 hours ago
05NOV2018:17:04:57 combine, exactly three hours ago (to the second)

Actually, your code is close to the result, i think you forgot to transfer SAS date format to display format.
using put function in variable target_minus_3hr_dt & target_minus_3hr_exact_dt,
since the SAS date is shown as numeric so we need to use put function to transfer.
data _null_;
APPLCTN_DT = '05NOV2018:00:00:00.000'dt ;
APPLCTN_TM = "20:04:57";
date_part = datepart(applctn_dt);
time_part = input(applctn_tm,time8.);
target_dt = put(date_part,date9.)||applctn_tm;
target_minus_3hr_dt = put((intnx ('dthour'
, dhms(date_part,0,0,0) + time_part
, -3
)),datetime20.);
target_minus_3hr_exact_dt = put((intnx ('dtsecond'
, dhms(date_part,0,0,0) + time_part
, -3*60*60
)),datetime20.);
put target_dt ' combined';
put target_minus_3hr_dt ' combined, 3 hours ago';
put target_minus_3hr_exact_dt ' combine, exactly three hours ago (to the second)';
run;

Related

Partition by date in Snowflake procedure removing leading zeros from date

I am trying to partition the data from a Snowflake table and storing it as a parquet file in a S3 bucket. This partition allows me to store the data organised by date (Bucket:///).
I am performing this, using the below Snowflake procedure:
However, this creates the folders structure in the following way:
And I wanted it to be: year=2022/month=05/day=01/
To accomplish this I changed month and day variables to:
However, it produced the same result that I was having before the change.
I even tried to assign some values to both 'day' and 'month' vars like:
var day = '01'
var month = '05'
But it is still removing the leading zeros from the month and day.
Do you know how can I solve this?
Thanks for your help.
You just need to add some additional lines of code to prefix the values with zero when required e.g. (pseudo-code)
day = if day < 10 then "0"||day else day;
month = if month < 10 then "0"||month else month;
You can use a Snowflake SQL to get the correct date format in MM and DD. Here is the SQL
SELECT TO_CHAR(CURRENT_DATE(), 'MM') MON, TO_CHAR(CURRENT_DATE(), 'DD');
and the stored proc to get the values
create or replace procedure date_test()
returns string
language javascript
as
$$
var day;
var mon;
// Dynamically compose the SQL statement to execute.
var sql_command = "SELECT TO_CHAR(CURRENT_DATE(), 'MM') MON, TO_CHAR(CURRENT_DATE(), 'DD');"
// Run the statement.
var stmt = snowflake.createStatement(
{
sqlText: sql_command
}
);
var res = stmt.execute();
res.next();
mon = res.getColumnValue(1);
day = res.getColumnValue(2);
return "day:" + day + " month:" + mon;
$$
;
call date_test();
output:
DATE_TEST
day:13 month:05

Convert string to datetime in cosmos db

In my cosmos db a date field is stored as string like this
{
"ValidationWeekStartDay": "27-Apr-2020"
}
I have to write a query to extract all documents whose ValidationWeekStartDay is greater than current date. How can I achieve this in cosmos db query?
Select * from c wher c.ValidationWeekStartDay > GetCurrentDateTime ()
this does not give me correct result.
This is the problem with date format, the documents you are storing is in format 'dd-MMM-yyyy' while GetCurrentDateTime() function gets the date in format 'yyyy-mm-dd....'. So when you run the above query, comparison like below happens:
'27-Apr-2020' > '2020-08-17'
It compares the characters one by one and first 2 characters of first value becomes greater than second value. For testing purpose, anything above date 20 will be returned by your query irrespective of any month.
There are 2 ways to resolve this.
Store the date in same format as GetCurrentDateTime() function.
Create a udf like below. You can create your own udf, this is just a sample one based on date format.(pardon the formatting, you can copy and run it as it is)
function formatdatetime(datetime){ datetime = datetime.substring(7,11) + '-' + datetime.substring(3,6) + '-' + datetime.substring(0,2); datetime = datetime.replace('Jan','01'); datetime = datetime.replace('Feb','02'); datetime = datetime.replace('Mar','03'); datetime = datetime.replace('Apr','04'); datetime = datetime.replace('May','05'); datetime = datetime.replace('Jun','06'); datetime = datetime.replace('Jul','07'); datetime = datetime.replace('Aug','08'); datetime = datetime.replace('Sep','09'); datetime = datetime.replace('Oct','10'); datetime = datetime.replace('Nov','11'); datetime = datetime.replace('Dec','12'); return datetime; }
And then use the below query:
select c.stdDates as stdDates from c Where udf.formatdatetime(c.stdDates) > GetCurrentDateTime ()

SQL Update Query: Counting records with current date

I have a column named ClientMigrated of the format 7/23/2019 7:56:45 AM
I have a query that is run within a macro to count the rows where the date portion of ClientMigrated is the current day.
UPDATE Tracking SET Tracking.UserMailboxesMigrated =
DCount("ClientMigrated","[Mailbox Status]","ClientMigrated=Date()")
WHERE (((Tracking.ReportingDate)=Date()));
The query returns nothing because ClientMigrated contains the timestamp part which does not equate to the date.
I've tried to wrap ClientMigrated in a format function so that it compares to Date():
format(ClientMigrated, "dd/mm/yyyy")=Date()
it seems is not acceptable syntax within DCount.
Suggestions to get around this is appreciated.
Consider DATEVALUE to extract the date portion of a date/time field:
UPDATE Tracking t
SET t.UserMailboxesMigrated = DCount("ClientMigrated",
"[Mailbox Status]",
"DATEVALUE(NZ(ClientMigrated, ""1900-01-01"")) = Date()")
WHERE (DATEVALUE(t.ReportingDate) = Date());
Nz should return a date value, not a string, for Null:
UPDATE Tracking t
SET t.UserMailboxesMigrated = DCount("ClientMigrated",
"[Mailbox Status]",
"DateValue(Nz(ClientMigrated, #00:00:00#)) = Date()")
WHERE DateValue(t.ReportingDate) = Date();
You need to utilize the FORMAT function
Assuming that you are using the default value for DATE(), you should be able to use:
UPDATE Tracking
SET Tracking.UserMailboxesMigrated =
DCount("ClientMigrated", "[Mailbox Status]", "ClientMigrated=Date()")
WHERE (((Format(Tracking.ReportingDate, "dd/mm/yyyy"))=Date()));
To use an index onClientMigratedyou should check the datetime field for being same or greater than today (Date()) and smaller than tomorrow (DateAdd(""d"", 1, Date()). The""escapes the double-quote for theDateAddinterval-parameter nested in theDCountcriteria string.
UPDATE Tracking
SET UserMailboxesMigrated = DCount("ClientMigrated",
"[Mailbox Status]",
"ClientMigrated >= Date() AND ClientMigrated < DateAdd(""d"", 1, Date())
WHERE ReportingDate = Date();
ReportingDateis a date not a datetime? If datetime, use same pattern, but you must not escapeDateAdddouble-quotes.

Concatenating date and time fields

I have a table invoices with this fields:
invDate -> a date field
invTime -> a time field
I need to do querys like
SELECT top 10 * from invoices WHERE DATETIME(invDate+invTime)
BETWEEN DATETIME('2013-12-17 17:58') AND DATETIME()
or something like that. I don't know how to concatenate the invDate and invTime to create a datetime field. The only thing that i could do is this horribly thing:
DATETIME( YEAR(invDate), MONTH(invDate), DAY(invDate), 17, 52 ) AS MyDatetime
Couldn't even get hour and time with hour(invTime) and minute(invTime):
DATETIME( YEAR(invDate), MONTH(invDate), DAY(invDate),
HOUR(invTime), MINUTE(invTime) ) AS MyDatetime
I'm doing the querys throught the VFP Odbc Driver via PHP.
You were pretty close. If the value coming from PHP is not of a date/time, how could VFP interpret it properly. VFP also has a function CTOT() (character to time), and expects it in the format of 'yyyy-mm-ddThh:MM:ss??'
yyyy = 4 digit year
mm = 1 OR 2 digit month
dd = 1 OR 2 digit day
T -- literally the letter "T"
hh = 1 OR 2 digit hour (but typical is 2 anyhow)
MM = 1 or 2 digit minute (but typical is 2)
ss = 1 or 2 digit for seconds -- not required
?? = "AM" or "PM" if you wanted to explicitly provide that vs 24 hour clock
The MM and ss are optional, so if you finished with "T1" would be 1:00:00am
Now, to finish your query.
WHERE DATETIME(invDate+invTime)
BETWEEN DATETIME('2013-12-17 17:58') AND DATETIME()
Since this appears to be querying all invoices between a given date/time and NOW (via DateTime()), you don't even need between, you can do
WHERE YourTable.Column > CTOT( '2013-12-17T17:58')
If you specifically DID have a date/time range to consider, THEN you could do something like
WHERE YourTable.Column BETWEEN CTOT( '2013-12-05T10:00') AND CTOT( '2013-12-14T11:58')
PROBLEMS WITH your DATE() and TIME() implementations
The problem is Date() is a function to either return current date, or create based on y/m/d provided such as date( 2013, 12, 7 ). If you are passing a string, use CTOD( 'mm/dd/yyyy' ) such as CTOD( 12, 7, 2013 ).
As for the TIME() function that just expects a number and is of no use for you. From the OleDbProvider, your best bet is to just create a php function that builds a single string in the CTOT() format I've described and pass to the php function the date and time fields. Then use that as your "CTOT( functionReturnResult )"
To add a Date and a Time Field together you will need to convert them both to a same datatype 1st and than just simply add them together something like this....
DECLARE #D DATE = '2013-12-17'
DECLARE #T TIME = '17:58:00'
SELECT CAST(#D AS DATETIME) + CAST(#T AS DATETIME)
Result
2013-12-17 17:58:00.000
Your Query
SELECT top 10 *
from invoices
WHERE CAST(invDate AS DATETIME) + CAST(invTime AS DATETIME)
BETWEEN '20131217 17:58:00.000' AND GETDATE()

SQL generate string from splitting another

I have a number of corrupt Dates in an Advantage database, but luckily I have a reverse date field which is intact.
I need to use SQL to recreate the Date field in the form 'DD/MM/YYYY' from the RDate string 'YYYYMMDD'.
Something equivalent to:
UPDATE table SET Date = FormatDate('DD/MM/YY',StrToDate('YYYYMMDD',RDate))
I don't know if this is possible to select character positions and use variables this way in SQL or if I'll have to write a program (in Delphi) to do the operation.
Thanks
Try something like
update table set
date = cast(substring(rdate, 5, 2) + '/' +
right(rdate, 2) + '/' +
left(rdate, 4) as date)
/* where ... */
(assuming your connection's date format setting is the default 'MM/DD/YYYY')
TOndrej I'm not sure if it was a syntax error or if cast is not recognised but I achieved the desired result with the following SQL:
update members set "Expiry Date" = ((substring(RExpiryDate,7,2)) + '/' + (substring(RExpiryDate,5,2)) + '/' + (substring(RExpiryDate,1,4)))
Thanks for your help