I have a table that stores data of when a shipment arrived and when it left. I need to subtract the OUT date from the IN date based on the ARRIVAL column and display in a separate table all the shipments that have been sitting for 5 days or more. How can this be done?
Here is my table -
ID | ARRIVAL | DATE |
---|---|---|
C1 | OUT | 2022-06-23 |
C1 | IN | 2022-06-18 |
C2 | OUT | 2022-06-20 |
C2 | IN | 2022-06-18 |
C3 | OUT | 2022-06-24 |
C3 | IN | 2022-06-17 |
Expected Result -
OVERSTAYED SHIPMENTS |
---|
C1 |
C3 |
CodePudding user response:
Test data:
create table my_table (id, arrival, date_col) as
select 'C1', 'OUT', date '2022-06-23' from dual union all
select 'C1', 'IN' , date '2022-06-18' from dual union all
select 'C2', 'OUT', date '2022-06-20' from dual union all
select 'C2', 'IN' , date '2022-06-18' from dual union all
select 'C3', 'OUT', date '2022-06-24' from dual union all
select 'C3', 'IN' , date '2022-06-17' from dual union all
select 'C4', 'IN' , date '2022-05-30' from dual union all
select 'C5', 'IN' , date '2022-06-20' from dual
;
Notice the last two rows, for id = C4, resp. C5. They only have an 'IN
' row, without an 'OUT'
row yet. In my answer, I will assume you want to find those id without an 'OUT'
row, if the 'IN'
row is currently (as of when the query is run) at least five days back.
date
is an Oracle keyword, it should not be used as a column name. I changed the name to date_col
; use your actual column name, which I hope is not date
.
Query and output:
select id
from my_table
pivot (min(date_col) for arrival in ('IN' as date_in, 'OUT' as date_out))
where date_in <= nvl(date_out, sysdate) - 5 -- example run on 2022-06-22
order by id -- or whatever you need
;
ID
--
C1
C3
C4
The pivot
operation is an aggregate operation; it avoids the join used in other answers, which generally requires the same data to be read twice.
CodePudding user response:
It's possible to compute add days to a date using " ". With that, it's possible to compare the dates.
SELECT i.id FROM events i JOIN events o ON i.id = o.id
WHERE i.arrival = 'IN'
AND o.arrival = 'OUT'
AND o.date >= i.date 5
In this case: i.date 5 adds 5 days to the date.
CodePudding user response:
You need to do a self-join to the one table based on the common id. However, I would SUGGEST doing a LEFT-JOIN meaning I want all from one side, regardless of an entry in the other. So, always start with an INBOUND item, left-join to a matching OUTBOUND. If there is no OUTBOUND version, then compute the days difference based on whatever the current date is. ie: if it still has not shipped out today, and its been 5 days already, why wait until someone gets to the shipment 9 days later to tell the staff to expedite the work, or find out what is up.
select
InRec.Id,
datediff( coalesce( OutRec.Date, CurDate() ), InRec.Date ) DaysToShip,
case when OutRec.Id is null then 'NOT SHIPPED' else '' end status
from
YourTable InRec
LEFT JOIN YourTable OutRec
on InRec.Id = OutRec.Id
AND OutRec.Arrival = 'OUT'
where
InRec.Arrival = 'IN'
AND datediff( coalesce( OutRec.Date, CurDate() ), InRec.Date ) >= 5
So, even though not specifically asked for, I included the calculation in the fields list so you can see the specific results.