Get Gap between time range - oracle

In WORK_TIME column in my database table (EMP_WORKS), i have records as below.
WORK_TIME
19:03:00
20:00:00
21:02:00
21:54:00
23:04:00
00:02:00
i want to create a database view using these data. for it i need to get Gap between these times as below.
WORK_TIME GAP
19:03:00 -
20:00:00 00:57:00 (Gap between 19:03:00 and 20:00:00)
21:02:00 01:02:00 (Gap between 20:00:00 and 21:02:00)
21:54:00 00:52:00 (Gap between 21:02:00 and 21:54:00)
23:04:00 01:10:00 (Gap between 21:54:00 and 23:04:00)
00:02:00 00:58:00 (Gap between 23:04:00 and 00:02:00)
How could i do this ?

This query will get you the differences in hours:
SELECT
work_time,
( work_time - LAG(work_time) OVER (ORDER BY work_time) ) * 24 AS gap
FROM emp_works
Example on SQL Fiddle returns this:
WORK_TIME GAP
November, 07 2012 19:03:00+0000 (null)
November, 07 2012 20:00:00+0000 0.95
November, 07 2012 21:02:00+0000 1.033333333333
November, 07 2012 21:54:00+0000 0.866666666667
November, 07 2012 23:04:00+0000 1.166666666667
November, 08 2012 00:02:00+0000 0.966666666667

First you will need to have a primary key in the table containing the DATE/TIME field.
I have set up this demo on SQL Fiddle .. Have a look
I have represented the gap as a factor of hours between the two times. You can manipulate the figure to represent minutes, or days, whatever.
SELECT
TO_CHAR(A.WORK_TIME,'HH24:MI:SS') WORK_FROM,
TO_CHAR(B.WORK_TIME,'HH24:MI:SS') WORK_TO,
ROUND(24*(B.WORK_TIME-A.WORK_TIME),2) GAP FROM
sample A,
SAMPLE B
WHERE A.ID+1 = B.ID(+)
If your primary key values have difference greater than 1 (gaps within the values of the primary key) then you will need to offset the value dynamically like this:
SELECT
TO_CHAR(A.WORK_TIME,'HH24:MI:SS') WORK_FROM,
TO_CHAR(B.WORK_TIME,'HH24:MI:SS') WORK_TO,
ROUND(24*(B.WORK_TIME-A.WORK_TIME),2) GAP FROM
sample A,
SAMPLE B
WHERE b.ID = (select min(C.ID) from sample c where c.id>A.ID)

According to your desired result, provided in the question, you want to see time interval. And also I suppose that the WORK_TIME column is of date datatype and there is a date part(otherwise there will be a negative result of subtraction (previous value of WORK_TIME from 00.02.00)).
SQL> create table Work_times(
2 work_time
3 ) as
4 (
5 select to_date('01.01.2012 19:03:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
6 select to_date('01.01.2012 20:00:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
7 select to_date('01.01.2012 21:02:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
8 select to_date('01.01.2012 21:54:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
9 select to_date('01.01.2012 23:04:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all
10 select to_date('02.01.2012 00:02:00', 'dd.mm.yyyy hh24:mi:ss') from dual
11 )
12 /
Table created
SQL>
SQL> select to_char(t.work_time, 'hh24.mi.ss') work_time
2 , (t.work_time -
3 lag(t.work_time) over(order by WORK_TIME)) day(1) to second(0) Res
4 from work_times t
5 ;
WORK_TIME RES
--------- -------------------------------------------------------------------------------
19.03.00
20.00.00 +0 00:57:00
21.02.00 +0 01:02:00
21.54.00 +0 00:52:00
23.04.00 +0 01:10:00
00.02.00 +0 00:58:00
6 rows selected

Related

Use EPOCH time for timestamp to get records within 1 minute

I was curious to see how in Oracle 12c you can take a timestamp datatype and convert the records into EPOCH time to make them a number and then use that number to find any records within that date column that are within 1 minute of each other (assuming the same day if needed, or simply any calculations within 1 minute).
I tried the following but got an ORA-01873: the leading precision of the interval is too small error.
select (sold_date - to_date('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS'))*86400 as epoch_sold_date from test1;
What is SOLD_DATE? For e.g. SYSDATE (function that returns DATE datatype), your code works OK.
SQL> select (sysdate
2 - to_date('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')
3 ) * 86400 as epoch_sold_date
4 from dual;
EPOCH_SOLD_DATE
---------------
1600807918
SQL>
As SOLD_DATE is a timestamp, but - it appears that fractions of a second aren't or special interest to you, cast it to DATE:
select (cast (systimestamp as date) --> this
- to_date('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')
) * 86400 as epoch_sold_date
from dual;
Saying that you get the same result for all rows: well, I don't, and you shouldn't either if SOLD_DATE differs.
SQL> with test (sold_date) as
2 (select timestamp '2020-09-22 00:00:00.000000' from dual union all
3 select timestamp '2015-03-18 00:00:00.000000' from dual
4 )
5 select sold_date,
6 (cast (sold_date as date)
7 - to_date('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')
8 ) * 86400 as epoch_sold_date
9 from test;
SOLD_DATE EPOCH_SOLD_DATE
------------------------------ ---------------
22.09.20 00:00:00,000000000 1600732800
18.03.15 00:00:00,000000000 1426636800
SQL>
One more edit: when you subtract two timestamps, result is interval day to second. If you extract minutes from it, you get what you wanted:
SQL> with test (sold_date) as
2 (select timestamp '2020-09-22 10:15:00.000000' from dual union all
3 select timestamp '2015-03-18 08:05:00.000000' from dual
4 )
5 select sold_date,
6 lead(sold_date) over (order by sold_date) next_sold_date,
7 --
8 lead(sold_date) over (order by sold_date) - sold_date diff,
9 --
10 extract(day from lead(sold_date) over (order by sold_date) - sold_date) diff_mins
11 from test
12 order by sold_date;
SOLD_DATE NEXT_SOLD_DATE DIFF DIFF_MINS
------------------------------ ------------------------------ ------------------------------ ----------
18.03.15 08:05:00,000000000 22.09.20 10:15:00,000000000 +000002015 02:10:00.000000000 2015
22.09.20 10:15:00,000000000
SQL>
In your case, you'd check whether extracted minutes value is larger than 1 (minute).
If you just want to see how many minutes are there between two timestamps, then
cast them to dates
subtract those dates (and you'll get number of days)
multiply it by 24 (as there are 24 hours in a day) and by 60 (as there are 60 minutes in an hour)
Something like this:
SQL> with test (date_1, date_2) as
2 (select timestamp '2020-09-22 10:15:00.000000',
3 timestamp '2020-09-22 08:05:00.000000' from dual
4 )
5 select (cast(date_1 as date) - cast(date_2 as date)) * 24 * 60 diff_minutes
6 from test;
DIFF_MINUTES
------------
130
SQL>
If you are just looking to compare dates and find rows that are within one minute of each other, you do not need to use epoch time. There are several solutions to this problem on this thread.

I have one requirement where I have to show the records between specific date and time every day of one week

I have one requirement where I have to show the records between specific date and time every day in one week duration.
in one week duration( 2019-04-01 till 2019-04-06) ,for instance record of 2019-04-01 at 19 PM till 8 Am of 2019-04-02 ,and record of 2019-04-02 at 19 PM till 08 AM of 2019-04-03 and ...
would you please help me!
Use recursive query to create proper periods then join with your data or do it simpler with condition like here:
select callbegin, callerno
from table4
where callerno in ('7032','750')
and callbegin between timestamp '2019-04-01 19:00:00'
and timestamp '2019-04-06 08:00:00'
and ('19' <= to_char(callbegin, 'hh24') or to_char(callbegin, 'hh24') < '08');
demo
Here's how I understood the question.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi';
Session altered.
SQL> break on period;
SQL> with
2 data (id, datum) as
3 (select 1, to_date('01.04.2019 15:30', 'dd.mm.yyyy hh24:mi') from dual union all
4 select 2, to_date('01.04.2019 20:00', 'dd.mm.yyyy hh24:mi') from dual union all -- 1st
5 select 3, to_date('02.04.2019 01:15', 'dd.mm.yyyy hh24:mi') from dual union all -- 1st perios
6 select 4, to_date('02.04.2019 11:00', 'dd.mm.yyyy hh24:mi') from dual union all
7 select 5, to_date('02.04.2019 23:15', 'dd.mm.yyyy hh24:mi') from dual union all -- 2nd period
8 select 6, to_date('03.04.2019 00:10', 'dd.mm.yyyy hh24:mi') from dual union all -- 2nd
9 select 7, to_date('04.04.2019 22:20', 'dd.mm.yyyy hh24:mi') from dual -- 3rd period
10 ),
11 test as
12 (select date '2019-04-01' dstart,
13 date '2019-04-06' dend
14 from dual
15 ),
16 inter as
17 (select dstart + level - 1 datum
18 from test
19 connect by level <= dend - dstart + 1
20 ),
21 from_to as
22 (select datum + 19/24 date_from,
23 lead(datum) over (order by datum) + 8/24 date_to
24 from inter
25 )
26 select f.date_From ||' - '|| f.date_to period,
27 d.id,
28 d.datum
29 from data d join from_to f on 1 = 1
30 where d.datum between f.date_from and f.date_to
31 order by f.date_From, d.id;
PERIOD ID DATUM
----------------------------------- ---------- ----------------
01.04.2019 19:00 - 02.04.2019 08:00 2 01.04.2019 20:00
3 02.04.2019 01:15
02.04.2019 19:00 - 03.04.2019 08:00 5 02.04.2019 23:15
6 03.04.2019 00:10
04.04.2019 19:00 - 05.04.2019 08:00 7 04.04.2019 22:20
SQL>
This is how to filter data by days and time by one week:
With date_list as (
Select
to_date(to_char( (sysdate - level), 'yyyymmdd') || '19', 'yyyymmddhh24') begin_time,
to_date(to_char( ((sysdate - level)+1), 'yyyymmdd') || '08', 'yyyymmddhh24') end_time
From dual connect by level <= 7
)
Select begin_time, your_table.*
From
your_table t1,
date_list t2
Where
t1.your_date between t2.begin_time and t2.end_time;

Oracle APEX - converting a field from collection to type DATE

I have a page that grabs data from apex collection and one of the fields is date but since it is coming from collection it comes up as text. What is the best way to convert it to date?
Generally speaking, text (string) is converted to DATE with TO_DATE function, by applying the correct format mask. For example:
SQL> with test (text_value) as
2 (select '23.04.2019' from dual union all
3 select '04-2019-23' from dual union all
4 select '04 April 2019' from dual
5 )
6 select to_date(text_value, 'dd.mm.yyyy') result from test
7 where text_value = '23.04.2019'
8 union all
9 select to_date(text_value, 'mm-yyyy-dd') from test
10 where text_Value = '04-2019-23'
11 union all
12 select to_date(text_value, 'dd month yyyy', 'nls_date_language=english')
13 from test
14 where text_value = '04 April 2019'
15 /
RESULT
----------
23/04/2019
23/04/2019
04/04/2019
SQL>

Identify Most Recent Record on Yearly Snapshot by partition of Arrange Id

I have Scenario Like below and want set Indicator based on Arrange Id, Login Date.. If User login website multiple time in Calendar Year then Most recent record need to set Y else N. Also I need to set Indicator like Bottom two rows as well.. ( Means 1121221 Accessed on last year recent 12/13/2017 need to set 'Y' and if user accessed in next immediate year 1/12/2018 then 'Y' )
enter image description here
Here's one option. What does it do?
the TEST CTE are some sample rows. Note ARRANGE_ID = 999, which has dates from 2017 and 2019 (which means that there are no consecutive years, so the date in 2019 should get the indicator 'N'. You didn't say, though, what would happen if there's yet another date in 2019; would both of them get 'N', or would the max login date still get a 'Y'?
the INTER CTE uses the MAX analytic function to find the maximum login date for the year and the LAG analytic function which returns the previous login date (so that I could check whether those years are consecutive or not)
the final query uses CASE to find whether certain row satisfies conditions to make the indicator equal to 'Y'
Here you go:
SQL> with test (arrange_id, login_date) as
2 (select 234, date '2017-02-18' from dual union all
3 select 234, date '2017-04-13' from dual union all
4 select 234, date '2017-11-14' from dual union all
5 select 234, date '2018-01-14' from dual union all
6 select 234, date '2018-09-11' from dual union all
7 select 234, date '2019-04-02' from dual union all
8 select 234, date '2019-05-18' from dual union all
9 select 112, date '2017-02-23' from dual union all
10 select 112, date '2017-12-13' from dual union all
11 select 112, date '2018-01-12' from dual union all
12 select 999, date '2017-01-01' from dual union all
13 select 999, date '2017-05-25' from dual union all
14 select 999, date '2019-01-01' from dual
15 ),
16 inter as
17 (select arrange_id,
18 login_date,
19 max(login_date) over
20 (partition by arrange_id, extract (year from login_date)) maxdate,
21 lag(login_date) over (partition by arrange_id order by login_date) prev_date
22 from test
23 )
24 select arrange_id,
25 login_date,
26 case when login_date = maxdate and
27 extract(year from login_date) - extract(year from prev_date) <= 1 then 'Y'
28 else 'N'
29 end indicator
30 from inter
31 order by arrange_id, login_date;
ARRANGE_ID LOGIN_DATE I
---------- ---------- -
112 02/23/2017 N
112 12/13/2017 Y -- Y because it is MAX in 2017
112 01/12/2018 Y -- Y because it is MAX in 2018 and 2018 follows 2017
234 02/18/2017 N
234 04/13/2017 N
234 11/14/2017 Y -- Y because it is MAX in 2017
234 01/14/2018 N
234 09/11/2018 Y -- Y because it is MAX in 2018 and 2018 follows 2017
234 04/02/2019 N
234 05/18/2019 Y -- Y because it is MAX in 2019 and 2019 follows 2018
999 01/01/2017 N
999 05/25/2017 Y -- Y because it is MAX in 2017
999 01/01/2019 N -- N because it is MAX in 2019, but 2019 doesn't follow 2017
13 rows selected.
SQL>

Oracle: TIMESTAMP data type

i am using timestamp for a field to store date and time, however when i fetch the rows from the table i get loads of zeros in the timestamp field.
SQL> select * from booking_session;
BK_ID|BK_DATE
----------|-------------------------
1|18-MAR-12 10.00.00.000000
2|18-MAR-12 10.25.00.000000
3|18-MAR-12 10.30.00.000000
4|18-MAR-12 10.35.00.000000
5|18-MAR-12 10.40.00.000000
The following is the insert statement
INSERT INTO BOOKING_SESSION VALUES (1,TO_TIMESTAMP('18/03/2012 10:00',
'DD/MM/YYYY HH24:MI')
Can someone please tell me how can the bk_date format be stored like 18-MAR-12 10.00 or at least have AM or PM next to it.
Thanks in advance.
You can declare BK_DATE column as timestamp(precision) where precision is a number of decimal digits to store fraction of a second. So you might have declared BK_DATE timestamp(0). If you do not need track time down to a fraction of a second use date data type to store dates. In any case time part (hh:mi:ss) will be there and if you insert data as you did, specifying only hour and minutes, then seconds will be fill in with zeros. You can use to_char function and appropriate date format mask to get rid of those trailing zeros at display time:
-- sample of data
SQL> with t1(BK_ID, BK_DATE) as(
2 select 1, to_timestamp('18-MAR-12 10.00.00.000000', 'DD-MON-RR HH:MI:SSxFF6') from dual union all
3 select 2, to_timestamp('18-MAR-12 10.25.00.000000', 'DD-MON-RR HH:MI:SSxFF6') from dual union all
4 select 3, to_timestamp('18-MAR-12 10.30.00.000000', 'DD-MON-RR HH:MI:SSxFF6') from dual union all
5 select 4, to_timestamp('18-MAR-12 10.35.00.000000', 'DD-MON-RR HH:MI:SSxFF6') from dual union all
6 select 5, to_timestamp('18-MAR-12 10.40.00.000000', 'DD-MON-RR HH:MI:SSxFF6') from dual
7 )
8 select bk_id
9 , to_char(bk_date, 'DD-MON-RR HH:MI') bk_date
10 from t1
11 ;
BK_ID BK_DATE
---------- ------------------------
1 18-MAR-12 10:00
2 18-MAR-12 10:25
3 18-MAR-12 10:30
4 18-MAR-12 10:35
5 18-MAR-12 10:40
Try the following query:
select * from booking_session where trunc(bk_date) = to_date('18-03-2012', 'dd-mm-yyyy');

Resources