简体   繁体   中英

SQL - How to subtract two DATE values in a column based on another column?

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

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM