I have a table that contains the time periods when an issuer calls the service. this table can have overlapping and non overlapping time periods:
with mht_issuer_revoked_call (issuerid, startdate, enddate) as (values
(4, to_date('25-11-2022', 'dd-mm-yyyy'), to_date('25-11-2022 12:00:00', 'dd-mm-yyyy hh24:mi:ss'),
(4, to_date('25-11-2022 12:00:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('26-11-2022', 'dd-mm-yyyy'),
(40, to_date('25-11-2022', 'dd-mm-yyyy'), to_date('25-11-2022 06:00:00', 'dd-mm-yyyy hh24:mi:ss'),
(40, to_date('25-11-2022 06:00:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('25-11-2022 12:00:00', 'dd-mm-yyyy hh24:mi:ss'),
(40, to_date('25-11-2022 11:30:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('25-11-2022 18:00:00', 'dd-mm-yyyy hh24:mi:ss'),
(40, to_date('25-11-2022 18:30:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('25-11-2022 19:30:00', 'dd-mm-yyyy hh24:mi:ss'),
(50, to_date('25-11-2022', 'dd-mm-yyyy'), to_date('25-11-2022 12:00:00', 'dd-mm-yyyy hh24:mi:ss'),
(50, to_date('25-11-2022 11:00:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('26-11-2022 01:30:00', 'dd-mm-yyyy hh24:mi:ss'),
(40, to_date('25-11-2022 19:31:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('26-11-2022', 'dd-mm-yyyy'),
(50, to_date('25-11-2022 23:10:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('25-11-2022 23:30:00', 'dd-mm-yyyy hh24:mi:ss'),
(50, to_date('25-11-2022 23:30:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('25-11-2022 23:45:00', 'dd-mm-yyyy hh24:mi:ss'),
(50, to_date('25-11-2022 23:50:00', 'dd-mm-yyyy hh24:mi:ss'), to_date('25-11-2022 23:55:00', 'dd-mm-yyyy hh24:mi:ss')
)
i managed to merge the time periods and new time periods dont have any overlapping with each other. my output is as follows:
with issuer_calls_merged (issuerid, start_date_time, end_date_time) as (values
(4 ,'11/25/2022' , '11/26/2022'),
(40 ,'11/25/2022', '11/25/2022 6:00:00 PM'),
(40 ,'11/25/2022 6:30:00 PM', '11/25/2022 7:30:00 PM'),
(40 ,'11/25/2022 7:31:00 PM', '11/26/2022' ),
(50 ,'11/25/2022', '11/26/2022 1:30:00 AM')
)
i am trying to write a procedure that gets FromDate and EndDate as input parameters and for each issuer calculates how many minutes are not covered according to retrieved FromDate and EndDate Parameters.
for example i will give these parameters:
FromDate := '11/20/2022'
EndDate := '11/28/2022'
then according to inserted time periods in issuer_calls table, for issuerid 40 i expect this output:
| issuerid | start_date_time(uncovered) | end_date_time(uncovered) | uncovered_time_minutes
| 40 | 11/20/2022 | 11/25/2022 | 7200
| 40 | 11/25/2022 6:00:00 PM | 11/25/2022 6:30:00 PM | 30
| 40 | 11/25/2022 7:30:00 PM | 11/25/2022 7:31:00 PM | 1
| 40 | 11/26/2022 | 11/28/2022 | 2880
i tried to do the job with procedure bellow:
create or replace procedure GAP(out_res out sys_refcursor,
in_FromDate mht_issuer_revoked_call.startdate%type,
in_EndDate mht_issuer_revoked_call.enddate%type
) AS
BEGIN
**-- i tried to compare the given time period(FromDate-EndDate) with previous merged time periods and calculate the gaps and then union with previous gap**
open out_res for
select ut.issuerid,
ut.startdate,
ut.enddate,
ut.initialgap as gap
from
(
with minStartDate as
(
select r.issuerid,
min(r.startdate) as min_StartDate
from mht_issuer_revoked_call r
group by r.issuerid
)
select m.issuerid,
in_FromDate as StartDate,
case
when m.min_StartDate >= in_EndDate then in_EndDate
else m.min_StartDate
end as EndDate,
case
when m.min_StartDate >= in_EndDate then (in_EndDate - in_FromDate + 1)*24*60
else (min_StartDate - in_FromDate + 1)*24*60
end as initialgap
from minStartDate m
union all
**--- bellow part merges the time periods and calculate the gaps between them**
SELECT issuerid,
end_date_time,
next_row_start,
(next_row_start - end_date_time)*24*60 as gap
from
(
SELECT issuerid,
start_date_time,
end_date_time,
case
when lead(start_date_time) over(partition by issuerid order by start_date_time) is null then end_date_time
else lead(start_date_time) over(partition by issuerid order by start_date_time)
end as next_row_start
FROM (
SELECT issuerid,
LAG( dt ) OVER ( PARTITION BY issuerid ORDER BY dt ) AS start_date_time,
dt AS end_date_time,
start_end
FROM (
SELECT issuerid,
dt,
CASE SUM( value ) OVER ( PARTITION BY issuerid ORDER BY dt ASC, value DESC, ROWNUM ) * value
WHEN 1 THEN 'start'
WHEN 0 THEN 'end'
END AS start_end
FROM mht_issuer_revoked_call
UNPIVOT ( dt FOR value IN ( startdate AS 1, enddate AS -1 ) )
)
WHERE start_end IS NOT NULL
)
WHERE start_end = 'end'
)
where (next_row_start - end_date_time) > 0
group by issuerid,next_row_start,end_date_time
) ut
order by ut.issuerid, ut.StartDate;
END gap;
but at the end i couldn't achieve the explained result above
You can get your result using just SQL and process it later. In this answer your FromDate And EndDate (P_FROM, P_UNTILL) are set to those from your question. You can define them as parameters or bind variables so you could change them. Comments are in the code.
WITH
tbl AS -- sample data
(
Select 4 "ID", To_Date('25.11.2022 00:00:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 12:00:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 4 "ID", To_Date('25.11.2022 12:00:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('26.11.2022 00:00:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 40 "ID", To_Date('25.11.2022 00:00:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 06:00:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 40 "ID", To_Date('25.11.2022 06:00:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 12:00:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 40 "ID", To_Date('25.11.2022 11:30:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 18:00:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 40 "ID", To_Date('25.11.2022 18:30:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 19:30:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 40 "ID", To_Date('25.11.2022 19:31:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('26.11.2022 00:00:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 50 "ID", To_Date('25.11.2022 00:00:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 12:00:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 50 "ID", To_Date('25.11.2022 11:00:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('26.11.2022 01:30:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 50 "ID", To_Date('25.11.2022 23:10:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 23:30:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 50 "ID", To_Date('25.11.2022 23:30:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 23:45:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual Union All
Select 50 "ID", To_Date('25.11.2022 23:50:00', 'dd.mm.yyyy hh24:mi:ss') "START_DATE", To_Date('25.11.2022 23:55:00', 'dd.mm.yyyy hh24:mi:ss') "END_DATE" From Dual
),
day_tbl AS -- create CTE to prepare your data
( Select ID,
ROW_NUMBER() OVER(Partition By ID Order By START_DATE) "RN", -- ordering ID events
START_DATE "START_DATE", To_Char(START_DATE, 'hh24:mi:ss') "START_TIME", -- just showing the time part of START_DATE
END_DATE "END_DATE", To_Char(END_DATE, 'hh24:mi:ss') "END_TIME", -- just showing the time part of END_DATE
--
To_Date('20.11.2022', 'dd.mm.yyyy') "P_FROM", -- column with P_FROM - you could define it as bind variable
To_Date('28.11.2022', 'dd.mm.yyyy') "P_UNTILL", -- column with P_FROM - you could define it as bind variable
( END_DATE - START_DATE ) * 24 * 60 "MINS" -- first calculation used for first and last row
From
(Select *
From ( -- for each ID create starting and ending row and union them with your data
Select ID "ID", START_DATE "START_DATE", END_DATE "END_DATE" From tbl Union ALL
Select ID, To_Date('20.11.2022', 'dd.mm.yyyy'), Min(START_DATE) From tbl GROUP BY ID Union All -- row with P_FROM as START_DATE - you could define it as bind variable
Select ID, Max(END_DATE), To_Date('28.11.2022', 'dd.mm.yyyy') From tbl GROUP BY ID -- row with P_UNTILL as END_DATE - you could define it as bind variable
)
Order By ID, START_DATE
)
)
SELECT
* -- you can select just the columns you need (not all of them like here)
FROM
( Select
ID, RN, START_DATE, START_TIME, END_DATE, END_TIME, P_FROM, P_UNTILL,
CASE WHEN RN = 1 Or RN = Max(RN) OVER(Partition By ID) THEN MINS -- first and last row already calculated
-- else --> second calculation for rows that are not first nor last
ELSE Round(( START_DATE - FIRST_VALUE(END_DATE) OVER(Partition By ID, TRUNC(START_DATE) Order By START_DATE Rows Between 1 Preceding And Current Row) ) * 24 * 60, 0)
END "MINS"
From
day_tbl
)
WHERE
MINS > 0 -- if you want just ID=40 here you can filter it
--
/* R e s u l t :
ID RN START_DATE START_TIME END_DATE END_TIME P_FROM P_UNTILL MINS
---------- ---------- ---------- ---------- --------- -------- --------- --------- ----------
4 1 20-NOV-22 00:00:00 25-NOV-22 00:00:00 20-NOV-22 28-NOV-22 7200
4 4 26-NOV-22 00:00:00 28-NOV-22 00:00:00 20-NOV-22 28-NOV-22 2880
40 1 20-NOV-22 00:00:00 25-NOV-22 00:00:00 20-NOV-22 28-NOV-22 7200
40 5 25-NOV-22 18:30:00 25-NOV-22 19:30:00 20-NOV-22 28-NOV-22 30
40 6 25-NOV-22 19:31:00 26-NOV-22 00:00:00 20-NOV-22 28-NOV-22 1
40 7 26-NOV-22 00:00:00 28-NOV-22 00:00:00 20-NOV-22 28-NOV-22 2880
50 1 20-NOV-22 00:00:00 25-NOV-22 00:00:00 20-NOV-22 28-NOV-22 7200
50 6 25-NOV-22 23:50:00 25-NOV-22 23:55:00 20-NOV-22 28-NOV-22 5
50 7 26-NOV-22 01:30:00 28-NOV-22 00:00:00 20-NOV-22 28-NOV-22 2790
*/
i think i could finally finish the job.
mht_issuer_revoked_call: this is the table whenever an issuer calls the service, issuerid, startdate and enddate are submitted.
MHT_ISSUER_MERGED_CALLS: the requests of issuers are merged and stored in this table.
MHT_ISSUER_UNIONED_CALLS: merged calls and input parameters are unioned and stored in this table.
create or replace procedure GAP(out_res out sys_refcursor,
in_FromDate mht_issuer_revoked_call.startdate%type,
in_EndDate mht_issuer_revoked_call.enddate%type
) as
BEGIN
delete from MHT_ISSUER_MERGED_CALLS;
commit;
insert into MHT_ISSUER_MERGED_CALLS (
select issuerid,
start_date_time as start_date,
end_date_time as end_date
FROM (
SELECT issuerid,
LAG(dt) OVER(PARTITION BY issuerid ORDER BY dt) AS start_date_time,
dt AS end_date_time,
start_end
FROM (
SELECT issuerid,
dt,
CASE SUM(value) OVER(PARTITION BY issuerid ORDER BY dt ASC, value DESC, ROWNUM) * value
WHEN 1 THEN 'start'
WHEN 0 THEN 'end'
END AS start_end
FROM mht_issuer_revoked_call UNPIVOT(dt FOR value IN(startdate AS 1, enddate AS - 1))
)
WHERE start_end IS NOT NULL
)
WHERE start_end = 'end');
commit;
delete from MHT_ISSUER_UNIONED_CALLS;
commit;
insert into MHT_ISSUER_UNIONED_CALLS
(
Select ISSUERID,
ROW_NUMBER() OVER(Partition By ISSUERID Order By START_DATE) "RN",
START_DATE "START_DATE",
To_Char(START_DATE, 'hh24:mi:ss') "START_TIME",
END_DATE "END_DATE",
To_Char(END_DATE, 'hh24:mi:ss') "END_TIME",
in_FromDate "P_FROM",
in_EndDate "P_UNTILL",
(END_DATE - START_DATE) * 24 * 60 "MINS"
From (
Select *
From (
Select issuerid "ISSUERID",
STARTDATE "START_DATE",
ENDDATE "END_DATE"
From MHT_ISSUER_MERGED_CALLS
Union ALL
Select issuerid,
case
when in_FromDate >= Min(STARTDATE) then Min(STARTDATE)
else in_FromDate
end,
case
when in_EndDate <= Min(STARTDATE) then in_EndDate
else Min(STARTDATE)
end
From MHT_ISSUER_MERGED_CALLS
GROUP BY issuerid
Union All
Select issuerid,
case
when Max(ENDDATE) <= in_FromDate then in_FromDate
else Max(ENDDATE)
end,
case
when in_EndDate <= Max(ENDDATE) then Max(ENDDATE)
else in_EndDate
end
From MHT_ISSUER_MERGED_CALLS
GROUP BY issuerid)
Order By ISSUERID, START_DATE ASC, END_DATE ASC
)
);
COMMIT;
open out_res for
select ISSUERID,
START_DATE AS START_DATE,
SELECTED_END_DATE AS END_DATE,
MINS AS GAP_MINUTES
from
(
Select ISSUERID,
RN,
START_DATE,
trunc(start_date),
START_TIME,
END_DATE,
END_TIME,
P_FROM,
P_UNTILL,
FIRST_VALUE(END_DATE) OVER(Partition By ISSUERID, TRUNC(START_DATE) Order By START_DATE Rows Between 1 Preceding And Current Row) as Selected_End_Date,
CASE
WHEN RN = 1 Or RN = Max(RN) OVER(Partition By ISSUERID) THEN MINS
ELSE
Round((START_DATE - FIRST_VALUE(END_DATE)OVER(Partition By ISSUERID, TRUNC(START_DATE) Order By START_DATE
Rows Between 1 Preceding And Current Row)) * 24 * 60,0)
END "MINS"
From MHT_ISSUER_UNIONED_CALLS
)
where mins > 0
and START_DATE >= in_FromDate and END_DATE <= in_EndDate;
END gap;
Need your help to frame a Oracle SQL query to capture non-working hours in a given month for the list of trips.
Values passed will be start date and end date
E.g.:
Feb has totally 696 hrs
Start Date End Date
S2 - 02-Feb-16 14:00 - 06-Feb-16 20:00 - 102hrs
S1 - 01-Feb-16 04:00 - 02-Feb-16 10:00 - 30hrs
Total Worked hrs - 132 hrs
The query result expected is 564 hrs
Attempted Query:
SELECT (a)
FROM (
SELECT COUNT( (SELECT DISTINCT 'O'
FROM TRIP s,
TRUCK p
WHERE s.TRUCKID = p.TRUCKID
AND p.NOTES2='ABC'
AND p.TRUCKID='553'
AND ( to_date(d,'DD-Mon-YYYY HH24')
NOT BETWEEN to_date(s.STIME,'DD-Mon-YYYY HH24')
AND to_date(s.ETIME,'DD-Mon-YYYY HH24')
)
) ) a
FROM (
SELECT (TRUNC(to_date(sysdate,'DD-MON-YYYY'),'MM') + level - 1) d
FROM dual
CONNECT BY level <= TO_CHAR(LAST_DAY(to_date(sysdate,'DD-MON-YYYY')),'DD')
)
)
WITH Trip_Dates ( Start_Date, End_Date ) AS (
SELECT TO_DATE( '2016-02-02 14:00:00', 'YYYY-MM-DD HH24:MI:SS' ), TO_DATE( '2016-02-06 20:00:00', 'YYYY-MM-DD HH24:MI:SS' ) FROM DUAL UNION ALL
SELECT TO_DATE( '2016-02-01 04:00:00', 'YYYY-MM-DD HH24:MI:SS' ), TO_DATE( '2016-02-02 10:00:00', 'YYYY-MM-DD HH24:MI:SS' ) FROM DUAL
)
SELECT ( ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), 1 ) - TRUNC( SYSDATE, 'MM' )
- SUM( End_Date - Start_Date ) ) * 24 AS Unworked_Hours
FROM Trip_Dates;
Outputs:
UNWORKED_HOURS
--------------
564
I have the following data:
ID SESSION START_DATE END_DATE
1 A 01/01/2016 22:35 02/01/2016 02:35
1 B 02/01/2016 02:35 02/01/2016 04:45
2 A 01/01/2016 00:00 01/01/2016 02:00
2 B 01/01/2016 02:00 01/01/2016 03:30
And I need to return like this:
ID SESSION START_DATE END_DATE
1 A 01/01/2016 22:35 01/01/2016 22:59
1 A 01/01/2016 23:00 01/01/2016 23:59
1 A 02/01/2016 00:00 02/01/2016 00:59
1 A 02/01/2016 01:00 02/01/2016 01:59
1 A 02/01/2016 02:00 02/01/2016 02:35
1 B 02/01/2016 02:35 02/01/2016 02:59
1 B 02/01/2016 03:00 02/01/2016 03:59
1 B 02/01/2016 04:00 02/01/2016 04:45
2 A 01/01/2016 00:00 01/01/2016 00:59
2 A ...
any help?
You can try something like this:
SELECT DISTINCT session,
id,
st,
end
FROM ( SELECT DECODE(LEVEL, 1, start_date, TRUNC(start_date, 'HH') + (LEVEL - 1) / 24) st,
PRIOR id p_id,
id,
PRIOR session p_session,
session,
LEAST(end_date, TRUNC(start_date, 'HH') + (LEVEL) / 24 - 1 / 24 / 60) end
FROM tab
CONNECT BY LEVEL <= EXTRACT(HOUR FROM end_date - start_date) + 1)
WHERE ( p_id = id
AND p_session = session)
OR (p_id IS NULL)
I would like to avoid the usage of DISTINCT, but could not find a way, hope someone else could give a better solution
Here is a solution, you just have to play a little with hour extractions:
create table connect_by_hour_test(id number, sess varchar2(1), start_date date, end_date date);
insert into connect_by_hour_test (id, sess, start_date, end_date) values (1, 'A', to_date('01/01/2016 22:30', 'dd/mm/yyyy hh24:mi'), to_date('02/01/2016 02:35', 'dd/mm/yyyy hh24:mi'));
insert into connect_by_hour_test (id, sess, start_date, end_date) values (1, 'B', to_date('02/01/2016 02:35', 'dd/mm/yyyy hh24:mi'), to_date('02/01/2016 04:45', 'dd/mm/yyyy hh24:mi'));
insert into connect_by_hour_test (id, sess, start_date, end_date) values (2, 'A', to_date('01/01/2016 00:00', 'dd/mm/yyyy hh24:mi'), to_date('01/01/2016 02:00', 'dd/mm/yyyy hh24:mi'));
insert into connect_by_hour_test (id, sess, start_date, end_date) values (2, 'B', to_date('01/01/2016 02:00', 'dd/mm/yyyy hh24:mi'), to_date('01/01/2016 03:30', 'dd/mm/yyyy hh24:mi'));
commit;
with max_level as (
select id, sess, ceil((end_date - start_date) / (1/24)) as val from connect_by_hour_test ) -- get the max number of iterations for each (id, sess) pair
select distinct
id,
sess,
decode(level, 1, to_char(start_date, 'dd/mm/yyyy hh24:mi'), to_char(trunc(start_date, 'hh24') + 1/24 * level - 1/24, 'dd/mm/yyyy hh24:mi')) start_date, -- if first iteration in pair show the start_date, otherwise show the start date, plus the number of hours for the current iteration(first iteration - 1 hour, 2nd iteration - two hours, etc) minus one minute
decode(level, (select val from max_level ml where ml.id = src.id and ml.sess = src.sess), to_char(end_date, 'dd/mm/yyyy hh24:mi'), to_char(trunc(start_date, 'hh24') + 1/24 * level - 1/24/60, 'dd/mm/yyyy hh24:mi')) end_date -- if last iteration show end_date, otherwise show value from previous iteration plus one minute
from
connect_by_hour_test src
connect by
trunc(start_date, 'hh24') + 1/24 * (level - 1) <= end_date order by 1,2;
Edit: Corrections made after feedback, added step to be level - 1 and max_level calculated as ceil, instead of trunc, of end_date - start_date
select level,
NR_ATENDIMENTO,
CD_SETOR_ATENDIMENTO,
greatest(DT_ENTRADA_UNIDADE, trunc(DT_ENTRADA_UNIDADE+(level-1)/24, 'hh24')) DT_ENTRADA_UNIDADE,
to_char(trunc(DT_ENTRADA_UNIDADE, 'hh24') + 1/24 * level - 1/24/60, 'dd/mm/yyyy hh24:mi:ss') DT_SAIDA_UNIDADE
from
(
SELECT
CD_SETOR_ATENDIMENTO,
NR_SEQ_INTERNO,
DT_ENTRADA_UNIDADE,
nvl(DT_SAIDA_UNIDADE,sysdate) DT_SAIDA_UNIDADE,
NR_ATENDIMENTO
FROM ATEND_PACIENTE_UNIDADE
WHERE OBTER_TIPO_UNIDADE_ATEND(NR_ATENDIMENTO, NR_SEQ_INTERNO, IE_PASSAGEM_SETOR) NOT IN ('S')
AND nr_atendimento = 831838
ORDER BY NR_ATENDIMENTO,
CD_SETOR_ATENDIMENTO,
DT_ENTRADA_UNIDADE DESC
)
WHERE 1=1
CONNECT BY ROWID=PRIOR ROWID
and trunc(DT_ENTRADA_UNIDADE, 'hh24') + 1/24 * (level - 1) <= nvl(DT_SAIDA_UNIDADE,sysdate)
AND PRIOR SYS_GUID() IS NOT NULL
order by 2,3,4;
I have two date_time fields. The first is the date_time of the sale and the second is the date_time the sales report is filed.
In order for the salesperson to obtain credit, the sales report has to be filed by midnight on the date after the sale was made.
I'm currently calculating the difference, and know that anything over 24 hours could be out of a qualifying time period. Also, there are times when the sales report is filed prior to the date_time of the sale.
I searched through previous answers and couldn't find anything similar.
You need something like:
select to_char(report_time, 'mm/dd/yyyy hh24:mi:ss') report_time,
to_char(sales_time, 'mm/dd/yyyy hh24:mi:ss') sales_time,
round((report_time - sales_time) * 24, 6) diff_in_hours,
case when report_time < trunc(sales_time) + 2 then 'Y' else 'N' end decision
from sales
Function trunc() cuts hours, minutes and seconds from sales_time. For instance for date 01/15/2015 11:59:00 it returns 01/15/2015 00:00:00.
Next we add 2 days to this result. Report_date has to be lower then this value. So:
report_time < trunc(sales_time) + 2
Test with sample data:
with sales as (select
to_date('01/15/2015 11:59:00', 'mm/dd/yyyy hh24:mi:ss') report_time,
to_date('01/15/2015 11:45:00', 'mm/dd/yyyy hh24:mi:ss') sales_time from dual
union all select
to_date('01/16/2015 23:59:00', 'mm/dd/yyyy hh24:mi:ss'),
to_date('01/15/2015 12:45:00', 'mm/dd/yyyy hh24:mi:ss') from dual
union all select
to_date('01/17/2015 00:00:01', 'mm/dd/yyyy hh24:mi:ss'),
to_date('01/15/2015 23:59:00', 'mm/dd/yyyy hh24:mi:ss') from dual)
select to_char(report_time, 'mm/dd/yyyy hh24:mi:ss') report_time,
to_char(sales_time, 'mm/dd/yyyy hh24:mi:ss') sales_time,
round((report_time - sales_time) * 24, 6) diff_in_hours,
case when report_time < trunc(sales_time) + 2 then 'Y' else 'N' end decision
from sales
Output:
REPORT_TIME SALES_TIME DIFF_IN_HOURS DECISION
------------------- ------------------- ------------- --------
01/15/2015 11:59:00 01/15/2015 11:45:00 0,233333 Y
01/16/2015 23:59:00 01/15/2015 12:45:00 35,233333 Y
01/17/2015 00:00:01 01/15/2015 23:59:00 24,016944 N
Consider the following (simplyfied) table:
ID NUMBER
PROD_NO VARCHAR2(10)
START_TIME DATE
What I want to do is selecting a 'window' of rows of size n around a given START_TIME.
Example:
ID PROD_NO START_TIME
...
42 1234567 2012-02-28 13:42:10
43 1234568 2012-02-28 13:47:53
44 1234569 2012-02-28 13:52:22
45 1234570 2012-02-28 13:59:01
46 1234571 2012-02-28 14:02:12
47 1234572 2012-02-28 14:05:19
...
Provided START_TIME = '2012-02-28 14:00:00' and window size n = 4 the resulting set of rows should be ID 44...47.
The entries cannot be assumed to be sorted by START_TIME. In case there are not enough entries available to match the specified window size, it may be cropped.
Since my SQL skills are pretty limited any help would be greatly appreciated.
Thanks in advance.
You can use analytic functions to help with this:
select WT.ID
from (select WT.ID
,max(
START_TIME)
over (order by START_TIME
rows between 2 preceding and 2 following)
as MAXST
,min(
START_TIME)
over (order by START_TIME
rows between 2 preceding and 2 following)
as MINST
from WT) WT
where MINST < to_date('2012-02-28 14:00:00', 'yyyy-mm-dd hh24:mi:ss')
and MAXST > to_date('2012-02-28 14:00:00', 'yyyy-mm-dd hh24:mi:ss')
This should work now:
SELECT *
FROM (SELECT id,
prod_no,
start_time,
ROWNUM rn,
datediff
FROM (SELECT id,
prod_no,
start_time,
start_time
- TO_DATE('01-JAN-2011 12:00:00',
'DD-MON-YYYY HH:MI:SS AM')
datediff
FROM table
WHERE start_time
- TO_DATE('01-JAN-2011 12:00:00',
'DD-MON-YYYY HH:MI:SS AM') > 0
ORDER BY datediff))
WHERE rn <= 2
UNION ALL
SELECT *
FROM (SELECT id,
prod_no,
start_time,
ROWNUM rn,
datediff
FROM (SELECT id,
prod_no,
start_time,
start_time
- TO_DATE('01-JAN-2011 12:00:00',
'DD-MON-YYYY HH:MI:SS AM')
datediff
FROM table
WHERE start_time
- TO_DATE('01-JAN-2011 12:00:00',
'DD-MON-YYYY HH:MI:SS AM') <= 0
ORDER BY datediff DESC))
WHERE rn <= 2