简体   繁体   中英

Is there a better way to write this Oracle SQL that deals with comparing dates in two different columns?

For a table in an Oracle 11g database:

CREATE TABLE mytable (START_DATE_TIME DATE, END_DATE_TIME DATE);
Insert into MYTABLE (START_DATE_TIME,END_DATE_TIME) values (to_date('06/20/2013 01:30:00 PM','MM/DD/YYYY HH:MI:SS AM'),to_date('06/20/2013 06:15:00 PM','MM/DD/YYYY HH:MI:SS AM'));
Insert into MYTABLE (START_DATE_TIME,END_DATE_TIME) values (to_date('06/21/2013 06:45:00 PM','MM/DD/YYYY HH:MI:SS AM'),to_date('06/22/2013 06:45:00 AM','MM/DD/YYYY HH:MI:SS AM'));
Insert into MYTABLE (START_DATE_TIME,END_DATE_TIME) values (to_date('06/23/2013 06:45:00 AM','MM/DD/YYYY HH:MI:SS AM'),to_date('06/23/2013 10:30:00 PM','MM/DD/YYYY HH:MI:SS AM'));
Insert into MYTABLE (START_DATE_TIME,END_DATE_TIME) values (to_date('06/25/2013 08:00:00 AM','MM/DD/YYYY HH:MI:SS AM'),to_date('06/25/2013 05:30:00 PM','MM/DD/YYYY HH:MI:SS AM'));
Insert into MYTABLE (START_DATE_TIME,END_DATE_TIME) values (to_date('06/25/2013 05:30:00 PM','MM/DD/YYYY HH:MI:SS AM'),to_date('06/26/2013 05:30:00 AM','MM/DD/YYYY HH:MI:SS AM'));
START_DATE_TIME         END_DATE_TIME
06/20/2013 01:30:00 PM  06/20/2013 06:15:00 PM
06/21/2013 06:45:00 PM  06/22/2013 06:45:00 AM
06/23/2013 06:45:00 AM  06/23/2013 10:30:00 PM
06/25/2013 08:00:00 AM  06/25/2013 05:30:00 PM
06/25/2013 05:30:00 PM  06/26/2013 05:30:00 AM

My goal is to find the hours between END_DATE_TIME and the next most recent START_DATE_TIME.

My query is :

SELECT start_date_time,
  end_date_time,
  ROUND((next_start_date - end_date_time)*24,2) hours_to_next_start
FROM
  (SELECT t.start_date_time,
    t.end_date_time,
    (SELECT MIN(t2.start_date_time)
    FROM mytable t2
    WHERE t2.start_date_time >= t.end_date_time
    ) next_start_date
  FROM mytable t
  ORDER BY t.start_date_time
  )

and I get the results:

START_DATE_TIME         END_DATE_TIME           HOURS_TO_NEXT_START 
06/20/2013 01:30:00 PM  06/20/2013 06:15:00 PM  24.5
06/21/2013 06:45:00 PM  06/22/2013 06:45:00 AM  24
06/23/2013 06:45:00 AM  06/23/2013 10:30:00 PM  33.5
06/25/2013 08:00:00 AM  06/25/2013 05:30:00 PM  0
06/25/2013 05:30:00 PM  06/26/2013 05:30:00 AM  NULL

It works fine as far as I know. But something tells me there might be a better, or at least newer, way to do this without the secondary query in the select?

What do you say?

There is a more "modern" way to do this, using the analytic LEAD function. I think it's better because it's more compact, plus once you get used to the analytic functions you'll find them easy to read - but that's just an opinion :)

SELECT
  Start_Date_Time,
  End_Date_Time,
  ROUND((next_start_date - end_date_time)*24,2) hours_to_next_start
FROM (
  SELECT
    Start_Date_Time,
    End_Date_Time,
    LEAD(Start_Date_Time) OVER (ORDER BY Start_Date_Time) AS   Next_Start_Date
  FROM myTable
)
ORDER BY Start_Date_Time

There's a SQL Fiddle here . To get more insight into how this works, try running the inner query on its own.

Use this query for getting diff hours between two date this will return as HH.MM

SELECT 
CONCAT
(
 DATEDIFF(MI,'06/20/2013 01:30:00 PM','06/20/2013 06:15:00 PM') / 60 ,'.', DATEDIFF(MI,'06/20/2013 01:30:00 PM','06/20/2013 06:15:00 PM') % 60
)

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