I want to find the day between two timestamps. The query must return an Integer value.
I have a column value and a fixed date (like t.movementdate and '2014-07-23 00:00:00.0').
You can try this
CREATE TABLE t (movementdate TIMESTAMP);
INSERT INTO t VALUES (TIMESTAMP '1014-07-21 03:23:02.0');
INSERT INTO t VALUES (TIMESTAMP '2014-07-22 10:54:02.0');
select actual_diff,extract (day from actual_diff)+
extract (hour from actual_diff)/24
+extract (minute from actual_diff)/(60*24)
+extract (second from actual_diff)/(60*60*24)
diff_in_days
from (select systimestamp- movementdate as actual_diff from t);
Good question. IMHO Oracle's timestamp arithmetic is quite ugly. If you need the difference in days, you can convert the TIMESTAMP to a DATE. Depending on your needs, you can also drop the minutes and hours with TRUNC. Once you have DATEs, you can simply substract them to get the difference in days:
CREATE TABLE t (movementdate TIMESTAMP);
INSERT INTO t VALUES (TIMESTAMP '2014-07-21 03:23:02.0');
INSERT INTO t VALUES (TIMESTAMP '2014-07-22 10:54:02.0');
SELECT t.movementdate, DATE '2014-07-23' - trunc(t.movementdate) as daydiff FROM t;
MOVEMENTDATE DAYDIFF
---------------------------- ----
21.07.2014 03:23:02,000000000 2
22.07.2014 10:54:02,000000000 1
Related
In Oracle SQL Developer, I have a table called t1 who have two columns col1 defined as NUMBER(19,0) and col2 defined as TIMESTAMP(3).
I have these rows
col1 col2
1 03/01/22 12:00:00,000000000
2 03/01/22 13:00:00,000000000
3 26/11/21 10:27:11,750000000
4 26/11/21 10:27:59,606000000
5 16/12/21 11:47:04,105000000
6 16/12/21 12:29:27,101000000
My sysdate looks like this:
select sysdate from dual;
SYSDATE
03/03/22
I want to create a stored procedure (SP) which will delete rows older than 2 months and displayed message n rows are deleted
But when i execute this statement
select * from t1 where to_date(TRUNC(col2), 'DD/MM/YY') < add_months(sysdate, -2);
I don't get the first 2 rows of my t1 table. I get more than 2 rows
1 03/01/22 12:00:00,000000000
2 03/01/22 13:00:00,000000000
How can i get these rows and deleted it please ?
In Oracle, a DATE data type is a binary data type consisting of 7 bytes (century, year-of-century, month, day, hour, minute and second). It ALWAYS has all of those components and it is NEVER stored with a particular formatting (such as DD/MM/RR).
Your client application (i.e. SQL Developer) may choose to DISPLAY the binary DATE value in a human readable manner by formatting it as DD/MM/RR but that is a function of the client application you are using and not the database.
When you show the entire value:
SELECT TO_CHAR(ADD_MONTHS(sysdate, -2), 'YYYY-MM-DD HH24:MI:SS') AS dt FROM DUAL;
Then it outputs (depending on time zone):
DT
2022-01-03 10:11:28
If you compare that to your values then you can see that 2022-01-03 12:00:00 is not "more than 2 months ago" so it will not be matched.
What you appear to want is not "more than 2 months ago" but "equal to or more than 2 months, ignoring the time component, ago"; which you can get using:
SELECT *
FROM t1
WHERE col2 < add_months(TRUNC(sysdate), -2) + INTERVAL '1' DAY;
or
SELECT *
FROM t1
WHERE TRUNC(col2) <= add_months(TRUNC(sysdate), -2);
(Note: the first query would use an index on col2 but the second query would not; it would require a function-based index on TRUNC(col2) instead.)
Also, don't use TO_DATE on a column that is already a DATE or TIMESTAMP data type. TO_DATE takes a string as the first argument and not a DATE or TIMESTAMP so Oracle will perform an implicit conversion using TO_CHAR and if the format models do not match then you will introduce errors (and since any user can set their own date format in their session parameters at any time then you may get errors for one user that are not present for other users and is very hard to debug).
db<>fiddle here
Perhaps just:
select *
from t1
where col2 < add_months(sysdate, -2);
I need to query 2 tables, one contains a TIMESTAMP(6) column, other contains a DATE column. I want to write a select statement that prints both values and diff between these two in third column.
SB_BATCH.B_CREATE_DT - timestamp
SB_MESSAGE.M_START_TIME - date
SELECT SB_BATCH.B_UID, SB_BATCH.B_CREATE_DT, SB_MESSAGE.M_START_TIME,
to_date(to_char(SB_BATCH.B_CREATE_DT), 'DD-MON-RR HH24:MI:SS') as time_in_minutes
FROM SB_BATCH, SB_MESSAGE
WHERE
SB_BATCH.B_UID = SB_MESSAGE.M_B_UID;
Result:
Error report -
SQL Error: ORA-01830: date format picture ends before converting entire input string
01830. 00000 - "date format picture ends before converting entire input string"
You can subtract two timestamps to get an INTERVAL DAY TO SECOND, from which you calculate how many minutes elapsed between the two timestamps. In order to convert SB_MESSAGE.M_START_TIME to a timestamp you can use CAST.
Note that I have also removed your implicit table join with an explicit INNER JOIN, moving the join condition to the ON clause.
SELECT t.B_UID,
t.B_CREATE_DT,
t.M_START_TIME,
EXTRACT(DAY FROM t.diff)*24*60 +
EXTRACT(HOUR FROM t.diff)*60 +
EXTRACT(MINUTE FROM t.diff) +
ROUND(EXTRACT(SECOND FROM t.diff) / 60.0) AS diff_in_minutes
FROM
(
SELECT SB_BATCH.B_UID,
SB_BATCH.B_CREATE_DT,
SB_MESSAGE.M_START_TIME,
SB_BATCH.B_CREATE_DT - CAST(SB_MESSAGE.M_START_TIME AS TIMESTAMP) AS diff
FROM SB_BATCH
INNER JOIN SB_MESSAGE
ON SB_BATCH.B_UID = SB_MESSAGE.M_B_UID
) t
Convert the timestamp to a date using cast(... as date). Then take the difference between the dates, which is a number - expressed in days, so if you want it in minutes, multiply by 24*60. Then round the result as needed. I made up a small example below to isolate just the steps needed to answer your question. (Note that your query has many other problems, for example you didn't actually take a difference of anything anywhere. If you need help with your query in general, please post it as a separate question.)
select ts, dt, round( (sysdate - cast(ts as date))*24*60, 2) as time_diff_in_minutes
from (select to_timestamp('2016-08-23 03:22:44.734000', 'yyyy-mm-dd hh24:mi:ss.ff') as ts,
sysdate as dt from dual )
;
TS DT TIME_DIFF_IN_MINUTES
-------------------------------- ------------------- --------------------
2016-08-23 03:22:44.734000000 2016-08-23 08:09:15 286.52
I'm trying to get a new date from the product of 'date' + 'time interval'.
Something like this.
'15/02/2016 18:00:00' + '+00 02:00:00.000000'
Expected result:
'15/02/2016 20:00:00'
But using the columns in database.
CREATE TABLE timerest
(
DATE_ASIGN DATE,
TIME_ASIGN INTERVAL DAY(2) TO SECOND(0)
);
Thanks for your help.
You can just add them together:
insert into timerest (date_asign, time_asign)
values (to_date('15/02/2016 18:00:00', 'DD/MM/YYYY HH24:MI:SS'),
to_dsinterval('+00 02:00:00.000000'));
alter session set NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI:SS';
select date_asign + time_asign from timerest;
DATE_ASIGN+TIME_ASIGN
---------------------
15/02/2016 20:00:00
This follows the rules for datetime/interval arithmetic: date + interval = date.
If you have a date in DATE format you can simply add the a numeric interval that represents days (for example 1.5 is 1 day and a half)
You can extract from the time interval days and hours and then add them to to you date because, if I remember correctly, you can't add directly them to a date type (maybe to a timestamp type you can)
To extract the days you can use the extract function:
(
extract(second from TIME_ASIGN)/3600)+(extract(hour from TIME_ASIGN)/24)+(extract(day from TIME_ASIGN)/24)
then you add the number to your DATE_ASIGN
How can i convert the result of select statement of time interval field in respective time in Am/Pm format.
My Field is:
Interval Day(2) To Second(6)
I tried this:
select To_Char(Att_EntranceTime , 'HH:MI AM') From EMPLOYEEATTENDENCETABLE;
however this does not help me, i have also tried to add the basetime from systime to my interval field but that did not help.. can someone suggest me what to do?
Intervals can't be directly formatted, as you've discovered. You can add your interval to any date which has its time set to midnight, and then format the resulting date to show the time in your desired format. For example you could add it to today's date using trunc(sysdate):
to_char(trunc(sysdate) + my_interval, 'HH:MI AM')
You need to truncate it to set the time to midnight; otherwise the result will be your interval plus the current system time.
Or you can use any fixed date; here's an example with some dummy data set-up:
create table my_table (my_interval interval day(2) to second(6));
insert into my_table (my_interval) values (interval '0 12:34:56.78' day to second);
insert into my_table (my_interval) values (interval '99 01:02:03.456' day to second);
select my_interval, to_char(date '1970-01-01' + my_interval, 'HH:MI AM') as formatted
from my_table;
MY_INTERVAL FORMATTED
-------------------- ---------
+00 12:34:56.780000 12:34 PM
+99 01:02:03.456000 01:02 AM
The second value shows a potential problem. Your interval is defined to allow a two-digit day number, which means the interval can span anything less than 100 days. If you only extract the time portion you lose that information about the number of days. That may be what you want to happen though. If the interval is supposed to be representing a time of day, which wanting to show AM/PM implies - and it's unusual to store an actual time separate from its date - then having or allowing a number of days seems strange.
This question already has answers here:
How to store only time; not date and time?
(5 answers)
Closed 8 years ago.
I would like to insert data to db as time, not date. If I use to_date('2012-08-31 07:39:33', 'YYYY-MM-DD HH24:MI:SS') it adds date too.
If I use to_date('09:34:00', 'HH24:MI:SS') it adds year, month, day as well, from nowhere :|
Later I need to get rows where time is between x and y, not taking in account the year, month or day. How do I do that?
thanks
As an alternative to the date solution Dave shows, you could use an interval data type for the column:
create table t42(id number, t interval day to second);
insert into t42 (id, t) values(123, to_dsinterval('0 07:39:33'));
insert into t42 (id, t) values(456, to_dsinterval('0 09:34:00'));
select id
from t42
where t between to_dsinterval('0 07:00:00') and to_dsinterval('0 07:59:59');
ID
----------
123
Displaying intervals is a little awkward as they don't have format models, but see this question for some ideas if needed. If you only use them for filtering then that may not be an issue at all.
A DATE type always includes the date component.
One option is to continue using DATE and write your code to ignore the date component. In order to make queries on the time efficient, you might want to create a function-based index on something like TO_CHAR( date_field, 'HH24:MI:SS' ) and use that expression in your queries.
Alternatively, you could use a NUMBER field to store the number of seconds since midnight, and write your queries in terms of that.
you can use number column type and insert value as
INSERT INTO table_name (nTime)
VALUES (date - trunc(date));
and then select values
select *
from table_name t
where t.nTime between (10 / 24 + 15 / 24 / 60) and (12 / 24 + 30 / 24 / 60) --between 10:15 and 12:30