How to get 24 hours back time from current time in Oracle - sql

I have a column in my Oracle db which records the creation time of a user in the following format
30-NOV-20 11.49.11.000000000 AM (TIMESTAMP(6) format).
What I wanted to do is select all records whose creation time is 24 hours earlier than current time
So what I was going to do was subtract 1 from current time and compare it. But when I subtract 1 it returns only the date.
select * from user where created_date < SYSTIMESTAMP-1
dbms_output.put_line (SYSTIMESTAMP-1);-->29-NOV-20
The time parts are missing which makes me unable to compare with created time in the table
Please help me to complete this task.

If you subtract 1 from a date datatype (e.g. sysdate), it'll move you back one day. But, if you subtract it from a timestamp datatype value, Oracle will convert it to date and return a date (moreover, it'll be truncated).
See the following example:
SQL> select
2 systimestamp val1,
3 systimestamp - 1 val2,
4 --
5 systimestamp - interval '1' day val3
6 from dual;
VAL1
-----------------------------------------------------
VAL2
--------
VAL3
-----------------------------------------------------
30.11.20 09:55:01,439352 +01:00
29.11.20
29.11.20 09:55:01,439352000 +01:00
SQL>
So, what you should do is to subtract an interval, i.e.
select *
from user
where created_date < systimestamp - interval '1' day;

Half the problem is that whatever client program is being used to display the values is using the default date format for their territory and that default format is set to DD-MON-RR.
You can change the NLS_DATE_FORMAT and NLS_TIMESTAMP_FORMAT session parameters and that will (assuming your client program uses them and not some internal settings) give you the output you are expecting:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF9';
ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF9TZR';
Then
SELECT SYSDATE, SYSTIMESTAMP FROM DUAL;
Outputs (depending on your system time zone):
SYSDATE | SYSTIMESTAMP
:------------------ | :----------------------------------
2020-11-30 10:12:22 | 2020-11-30 10:12:22.476282000+00:00
If you use SYSTIMESTAMP-1 then Oracle does not support subtracting a NUMBER data type from a TIMESTAMP [WITH TIME ZONE] data type but it does support subtracting a NUMBER data type from a DATE data type and will perform an implicit cast from TIMESTAMP to DATE so that the query is valid.
For example:
SELECT SYSDATE - 1, SYSTIMESTAMP - 1, SYSTIMESTAMP - INTERVAL '1' DAY FROM DUAL;
Outputs:
SYSDATE-1 | SYSTIMESTAMP-1 | SYSTIMESTAMP-INTERVAL'1'DAY
:------------------ | :------------------ | :----------------------------------
2020-11-29 10:24:02 | 2020-11-29 10:24:02 | 2020-11-29 10:24:02.651735000+00:00
You can see that in the middle column SYSTIMESTAMP-1 gives the same output as SYSDATE-1 but in the right-hand column, subtracting an interval has ensured that TIMESTAMP WITH TIME ZONE data type is maintained.
So your query:
SELECT * FROM user WHERE created_date < SYSTIMESTAMP-1
Is effectively:
SELECT * FROM user WHERE created_date < CAST( SYSTIMESTAMP AS DATE )-1
Which will have exactly the same year, month, day, hour, minute and (integer) second components but will lose the fractional seconds and time zone information from the SYSTIMESTAMP.
If your column does not have time zone data and the level of precision in the fractional seconds does not matter to you then your query will work adequately.
However, if you want to keep the time zone and/or fractional seconds information then you can use:
SELECT * FROM user WHERE created_date < SYSTIMESTAMP - INTERVAL '1' DAY;
However, if created_date is a DATE column, you probably want:
SELECT * FROM user WHERE created_date < SYSDATE - INTERVAL '1' DAY;
or
SELECT * FROM user WHERE created_date < SYSDATE - 1;
db<>fiddle here

You can use it as (SYSDATE, -1).
Also, if you want to search for new records within 24 hours, it should be "created_date> = (sysdate-1)".

Related

How to pass timestamp value in Oracle Stored Procedure?

I have a table column which has timestamp data type. How to pass timestamp value to the table column? I am passing to_timestamp('1240','HH:MI:SS') in oracle procedure. In DB table I have a value like 01-AUG-20 12.40.00.000000000 PM . I only want to store timestamp in the DB table. Is there a way? Please guide me on this. Thanks
You appear to be confused about what the values store. A TIMESTAMP data type stores a date and time with year, month, day, hour, minute, second and optional fractional seconds and time zone components; you cannot have a TIMESTAMP with just hour, minute and second components as it will always have year-day components.
If you want to store time then either:
Use an INTERVAL DAY TO SECOND data type (with zero days);
Use a DATE (or, if you want fractional seconds, TIMESTAMP) data type and set the year-day components to a fixed value (or ignore them);
Use a string in a fixed format; or
Store the number of seconds after midnight and use TO_DATE( value, 'SSSSS' ) to convert to a date and then TO_CHAR to format it as needed.
I would say that if you want to add times then use an INTERVAL data type as it will natively support that.
For example:
CREATE TABLE times1 ( value INTERVAL DAY TO SECOND );
INSERT INTO times1 ( value ) VALUES ( INTERVAL '12:40' HOUR TO MINUTE );
SELECT * FROM times1;
Which outputs:
| VALUE |
| :------------------ |
| +00 12:40:00.000000 |
If you want to display times then use a DATE and ignore the year-to-day components as you can easily format the time using TO_CHAR.
For example:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
CREATE TABLE times2 ( value DATE );
INSERT INTO times2 ( value )
-- Fixed date
SELECT DATE '1970-01-01' + INTERVAL '12:40' HOUR TO MINUTE FROM DUAL UNION ALL
-- Today's date
SELECT TRUNC( SYSDATE ) + INTERVAL '12:40' HOUR TO MINUTE FROM DUAL UNION ALL
-- First of current month
SELECT TO_DATE( '12:40', 'HH24:MI' ) FROM DUAL;
SELECT value, TO_CHAR( value, 'HH24:MI' ) FROM times2;
Which outputs:
VALUE | TO_CHAR(VALUE,'HH24:MI')
:------------------ | :-----------------------
1970-01-01 12:40:00 | 12:40
2020-08-05 12:40:00 | 12:40
2020-08-01 12:40:00 | 12:40
db<>fiddle here

to_Char(DATE) with time

I have a DB (Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production). In there is a table (Course) in which I have a Date column (start_dte). I want to format the output to a char so I used:
SELECT start_dte,
to_Char(start_dte) AS start_dte_2,
to_Char(start_dte,'DD.MM.YYYY') AS start_dte_3,
to_Char(start_dte,'DD.MM.YYYY HH24:MI:SS') AS start_dte_4,
to_Char(start_dte,'DD.MM.YYYY HH12:MI:SS') AS start_dte_5,
to_Char(start_dte,'DD.MM.YYYY HH.MI.SSXFF AM') AS start_dte_6,
to_Char(start_dte,'DD.MM.YYYY HH24:MI:SSxFF') AS start_dte_7,
to_Char(start_dte,'DD-MON-YYYY HH24:MI:SSxFF TZH:TZM') AS start_dte_8
FROM Course
The Results:
Number 6,7,8 give me
java.sql.SQLException: ORA-01821: date format not recognized
6 has the same format as:
SELECT value
FROM V$NLS_PARAMETERS
WHERE parameter = 'NLS_TIME_FORMAT'
7 and 8 are taken from the Oracle documentation but this is only for timestamps. So what i am missing? I know the actual datatype should be datetime but I only have read access to that DB. What i would actually like:
Or even better:
A DATE doesn't have any time zone information, so if you want to adjust the displayed time then you'll need to specify which time zone that date nominally represents, and which time zone you want to convert it to.
An an example, if your stored date represents UTC and you want to see the equivalent local time in Paris, you can state that the stored time is UTC by casting it as a plain timestamp and passing that into the from_tz() function; and then specify the target timezone with at:
-- CTE for your sample data
with course (start_dte) as (
select cast(timestamp '2018-10-17 14:00:00' as date) from dual
)
-- actual query
select from_tz(cast(start_dte as timestamp), 'UTC')
at time zone 'Europe/Paris' as start_timestamp_tz
from course;
START_TIMESTAMP_TZ
------------------------------------------
2018-10-17 16:00:00.000000000 EUROPE/PARIS
Since you're querying this via JDBC you probably want to retrieve that as its native data type, and then choose how to display it locally. (But you could presumably query it as a date and adjust it in Java too...)
If you want to convert it to a string on the DB side, though, just use the format model you already used:
select to_char(from_tz(cast(start_dte as timestamp), 'UTC')
at time zone 'Europe/Paris', 'DD.MM.YYYY HH24:MI') as start_date
from course;
START_DATE
----------------
17.10.2018 16:00
Getting it into two fields is also simple, and if you don't want to repeat the conversion you can use a CTE or an inline view:
select to_char(start_timestamp_tz, 'DD.MM.YYYY') as start_date,
to_char(start_timestamp_tz, 'HH24:MI') as start_time
from (
select from_tz(cast(start_dte as timestamp), 'UTC')
at time zone 'Europe/Paris' as start_timestamp_tz
from course
);
START_DATE START_TIME
---------- ----------
17.10.2018 16:00
But it sounds like Java should be doing that conversion to strings for display.
What i would actually like:
| START_DATE |
|------------------|
| 17.10.2018 16:00 |
Or even better:
| START_DATE | START_TIME |
|------------|------------|
| 17.10.2018 | 16:00 |
Use:
SELECT to_Char(start_dte,'DD.MM.YYYY') AS start_date,
to_Char(start_dte,'HH24:MI') AS start_time
FROM Course
If your data is stored in the table in one time zone (i.e. UTC) and you want it in another time zone then use:
CAST( date_value AS TIMESTAMP ) to convert it from a DATE data type to a TIMESTAMP data type.
FROM_TZ( timestamp_value, timezone_string ) to convert it from a TIMESTAMP data type to a TIMESTAMP WITH TIME ZONE data type at the given time zone.
timestamp_with_timezone_value AT TIME ZONE timezone_string to convert it from one time zone to another time zone.
Like this:
SELECT TO_CHAR(
FROM_TZ( CAST( start_dte AS TIMESTAMP ), 'UTC' ) AT TIME ZONE 'Europe/Berlin',
'DD.MM.YYYY'
) AS start_date,
TO_CHAR(
FROM_TZ( CAST( start_dte AS TIMESTAMP ), 'UTC' ) AT TIME ZONE 'Europe/Berlin',
'HH24:MI'
) AS start_time
FROM Course
start_dte is a DATE value.
DATE does neither have fractional seconds (i.e. XFF) nor time zone information (i.e. TZH:TZM)
Use TIMESTAMP WITH TIME ZONE is you like to get such output.

Select data between timestamps

Usecase: Query to select the records for a whole day and it should run regularly.
This is my query.
Select to_char(in_date + interval '12' hour, 'DD-MON-YYYY HH24:MI:SS')
from my_table
where incoming_date > sysdate-2 and incoming_date < sysdate
I need to select yesterday's data only. Because of the conversion in the select statement I got today's data also. How do I select only yesterday's data? My DB is in UTC+7.00 standard. I need to display it in local standard so that I did a conversion in select statement. And how do I display only yesterday's data?
I'm stuck. Please help me
To get all data from yesterday you should use
SELECT TO_CHAR(IN_DATE + INTERVAL '12' HOUR, 'DD-MON-YYYY HH24:MI:SS')
FROM MY_TABLE
WHERE INCOMING_DATE BETWEEN TRUNC(SYSDATE) - INTERVAL '1' DAY
AND TRUNC(SYSDATE) - INTERVAL '1' SECOND
If, for example, SYSDATE is 05-NOV-2017 18:56:35, the time interval used in the BETWEEN comparison will be from 04-NOV-2017 00:00:00 to 04-NOV-2017 23:59:59. BETWEEN comparisons are inclusive of both endpoints so this will only return data with an INCOMING_DATE of sometime on 04-NOV-2017, in this example.
Best of luck.
only to get the
yesterday's data
make your
WHERE condition as
incoming_date between trunc(sysdate) - interval '1' day and trunc(sysdate) - interval '1' second
My DB is in UTC+7.00 standard. I need to display it in local standard so that I did a conversion in select statement.
Using a magic value (INTERVAL '12' HOUR) does not describe what it means or the assumptions you made when chosing that value. Instead you can better describe the process by using FROM_TS( timestampvalue, timezonestring ) to convert the value from a TIMESTAMP to a TIMESTAMP WITH TIME ZONE data type and then use AT LOCAL TIME to convert it to the local time. Then if you have daylight savings time or port the query to another international location then it will still display in the current local time. Like this:
SELECT TO_CHAR(
FROM_TZ( CAST( in_date AS TIMESTAMP ), '+07:00' ) AT LOCAL TIME,
'DD-MON-YYYY HH24:MI:SS'
)
FROM my_table
WHERE incoming_date >= TRUNC( SYSDATE ) - INTERVAL '1' DAY
AND incoming_date < TRUNC( SYSDATE )
And how do I display only yesterday's data?
TRUNC( SYSDATE ) will truncate today's date back to midnight. To get yesterday's data then you can get values that are greater or equal to TRUNC( SYSDATE ) - INTERVAL '1' DAY (one day before midnight today) and also less than TRUNC( SYSDATE ) (midnight today).
I'm not exactly sure I get your question, but I think I can explain some stuff.
I'll be assuming your table is a bit like this:
date_added | some_data | some_more_data
------------|-----------|----------------
date | data1 | data2
As I understand your goal is to fetch all the rows that were added to a table the day before the query is run using a select statement. but your current attempt fails at doing so by also returning today's results.
Here is what's happening (I think):
SYSDATE doesn't just give you the current date, it also gives you the time. You can see that for your self by simply altering your current session and setting the date/time format to one that includes both time and date
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY HH24:MI:SS';
The reason why you would be getting today's rows is simple, your query is asking for all the rows who's date_added field is between right now and right now - 24 hours. Not today and today - 24 hours.
So what is the solution?
Use the TRUNC function to trim the SYSDATE to the day instead!
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions201.htm
SELECT
T.*
FROM
MY_TABLE T
WHERE
T.DATE_ADDED BETWEEN (TRUNC(SYSDATE,'day') - 1) AND TRUNC(SYSDATE,'day');
As you did mention timezones being a thing keep in mind that SYSDATE returns the date on the server itself and not your computer's.
More on that here: https://stackoverflow.com/a/17925834/7655979
Usually I compare the date only using Trunc.
WHERE trunc(incoming_date) = trunc(sysdate-1)

Get today's date - Different timezone

I just wanted to know whether the following SQL is good to convert US server time to Thailand date. As we have 12 hours difference in the time, and TH time is ahead of U.S time
SELECT TO_DATE(
TO_CHAR(
SYSTIMESTAMP AT TIME ZONE 'Asia/Bangkok', 'yyyy-mm-dd',
'NLS_DATE_LANGUAGE = american'), 'yyyy-mm-dd') AS TODAY
FROM dual;
It works perfectly fine. But are there any other better way to convert timestamp of server from one timezone to another as I need to compare today's date based on this result in my outer SQL.
You could CAST the timestamp to your desired timezone.
For example,
SQL> WITH data AS (
2 SELECT SYSTIMESTAMP AT TIME ZONE 'Asia/Bangkok' tm_bangkok FROM dual
3 )
4 SELECT tm_bangkok,
5 CAST(tm_bangkok AT TIME ZONE 'EST' AS TIMESTAMP) tm_est
6 FROM data;
TM_BANGKOK TM_EST
--------------------------------------------- ----------------------------
03-NOV-15 12.54.18.951000 PM ASIA/BANGKOK 03-NOV-15 12.54.18.951000 AM
There is no reason to cast a TIMESTAMP to CHAR and then back to TIMESTAMP again. Simply do
SELECT SYSTIMESTAMP AT TIME ZONE 'Asia/Bangkok' AS TODAY
FROM dual;

How can query last 5 minutes of records?

How I can to see last 5 mins record before the current time through sql query how i can do this.
The format of time stamp is
03/25/2014 14:00:00
I used this query for the same
SELECT Time stamp FROM TABLE
WHERE S >1 AND SUBSTRING((Time stamp,15,2)-5)
is this fine of any other way to do the same
If you are using MySQL and your timestamp column is of data type datetime you can do
SELECT Timestamp
FROM your_table
WHERE Timestamp >= now() - interval 5 minute
If your timestamp is a date column, you can simply do:
select t.*
from table t
where t.timestamp >= sysdate - 5/(24*60)
Things are a bit more interesting if timestamp is a character column. Then you need to translate it to a date/time:
select t.*
from table t
where to_date(t.timestamp, 'MM/DD/YYYY HH24:MI:SS') >= sysdate - 5/(24*60)
select *
from the_table
where timestamp_column <= timestamp '2014-03-25 14:00:00' - interval '5' minute;
This assumes that timestamp_column is defined with the data type timestamp.
If it isn't you should stop now and re-define your table to use the correct data type.
The expression timestamp '2014-03-25 14:00:00' is a (ANSI SQL) timestamp literal.
It's equivalent to to_timestamp('2014-03-25 14:00:00', 'yyyy-mm-dd hh24:mi:ss') but I prefer the ANSI literal because it's less typing and works across multiple DBMS.
Here's an example of how to get 5 minutes ago in oracle. subtracting from a timestamp in increments of 1 where 1 is a day. so 5 minutes would be 5/(24hours*60min) of a day.
SELECT sysdate, sysdate-(5/(24*60)) as min_Ago5 from dual