Oracle SQL MIN and MAX combination from same table

坚强是说给别人听的谎言 提交于 2019-12-23 04:37:30

问题


I have below mentioned data. I am looking to get max of Start message and corresponding min or success message.

Start Message Table
ID1     Timestamp_start_msg_recieved    date        jobid      message time in seconds
1234    5/14/2014 10:02:29              5/14/2014   abc        start 262
1234    5/14/2014 10:02:31              5/14/2014   abc        start 264
1234    5/14/2014 10:02:45              5/14/2014   abc        start 278
1234    5/14/2014 10:02:50              5/14/2014   abc        start 285
1234    5/14/2014 10:09:04              5/14/2014   abc        start 165
1234    5/14/2014 10:09:06              5/14/2014   abc        start 2167
1234    5/14/2014 10:09:16              5/14/2014   abc        start 2180
1234    5/14/2014 10:09:26              5/14/2014   abc        start 2190
1234    5/14/2014 11:45:11              5/14/2014   abc        start 8767
1234    5/14/2014 16:48:20              5/14/2014   abc        start 878
1234    5/14/2014 19:02:52              5/14/2014   abc        start 687
5678    5/14/2014 22:02:52              5/14/2014   pqr        start 501
5678    5/14/2014 23:10:40              5/14/2014   pqr        start 200
Success Message Table
ID1     Timestamp_success_msg_recieved  date        jobid  message time in seconds
1234    5/14/2014 10:02:52              5/14/2014   abc    successful 290
1234    5/14/2014 10:09:32              5/14/2014   abc    successful 4280 
1234    5/14/2014 11:45:15              5/14/2014   abc    successful 8774
1234    5/14/2014 11:45:18              5/14/2014   abc    successful 8777
1234    5/14/2014 11:45:19              5/14/2014   abc    successful 8778
1234    5/14/2014 11:45:25              5/14/2014   abc    successful 8784
1234    5/14/2014 16:48:22              5/14/2014   abc    successful 880 
1234    5/14/2014 19:03:00              5/14/2014   abc    successful 699
5678    5/14/2014 22:03:00              5/14/2014   pqr    successful 250
5678    5/19/2014 14:00:16              5/19/2014   pqr    successful 400

Expected Result

ID1  IMESTAMP_for_start_message TIMESTAMP_for_success_message    Date       Jobid    msg  msg start_secs success_secs
1234 5/14/2014 10:02:50         5/14/2014 10:02:52           5/14/2014  abc start success 262 290 
1234 5/14/2014 10:09:26         5/14/2014 10:09:32           5/14/2014  abc start success 2190 4280
1234 5/14/2014 11:45:11         5/14/2014 11:45:25           5/14/2014  abc start success 8767 8784
1234 5/14/2014 16:48:20         5/14/2014 16:48:22           5/14/2014  abc start success 878 880
1234 5/14/2014 19:02:52         5/14/2014 19:03:00           5/14/2014  abc start success 687 699
5678 5/14/2014 22:02:52         5/14/2014 22:03:00           5/14/2014  pqr start success 501 699
5678 5/14/2014 23:10:40         null                         5/14/2014  pqr start success 250 null
5678    null                   5/19/2014 14:00:16            5/19/2014  pqr null  success null 400

I am looking for Max of start message and start_secs to pair up with min of success message and success_secs. Tried using Temporary table using WITH clause and also used self join method. Below is my query, But WITH clause query returns MIN of overall data in the table.

Query Used:

WITH DATA AS
  (SELECT MIN(smt.column13) timestamp_for_success_message
  FROM success_table1 smt, start_table2 b
     WHERE
    (SMT.id1 = b.id1)
    AND (SMT.jobid = b.jobid)
    AND (SMT.timestamp_for_success_message_recieved >= b.timestamp_for_start_message_recieved)
  )
SELECT distinct a.timestamp_for_success_message_recieved,
  b.timestamp_for_start_message_recieved,
  b.id1,
  b.jobid
FROM data a,
  start_table2 b
order by b.timestamp_start_message_recieved, a.timestamp_for_success_message_recieved, b.jobid, b.id1;

回答1:


For the sample data, the following works as well

WITH
RawData AS (
  SELECT
    id1
    , jobID
    , message
    , TIMESTAMP_for_start_message timeStamp
    , time_in_seconds
  FROM StartMessageTable
  UNION ALL
  SELECT
    id1
    , jobID
    , message
    , TIMESTAMP_success_msg_received
    , time_in_seconds
  FROM SuccessMessageTable
  ORDER BY id1, jobID, 4
),
Detail AS (
  SELECT
    id1
    , jobID
    , message message1
    , LEAD (message, 1) OVER (ORDER BY id1, jobID, timeStamp) message2
    , timeStamp timeStamp1
    , LEAD (timeStamp, 1) OVER (ORDER BY id1, jobID, timeStamp) timeStamp2
    , time_in_seconds secs1
    , LEAD (time_in_seconds, 1) OVER (ORDER BY id1, jobID, timeStamp) secs2
  FROM RawData
)
SELECT
  id1
  , timeStamp1 TIMESTAMP_for_start_message
  , timeStamp2 TIMESTAMP_for_success_message
  , jobID
  , 'start' msgStart
  , 'success' msgSuccess
  , secs1 start_secs
  , secs2 success_secs
FROM Detail
WHERE (message1 = 'start' AND message2 = 'successful') OR message2 IS NULL
ORDER BY timeStamp1
;

with the same caveat regarding the first and last value in the "start_secs" column.
SQL Fiddle




回答2:


Edit: According to OP's feedback, the query fails for the live data. This is likely due to
GROUP BY (TRUNC(TIMESTAMP_for_start_message, 'MI'))
not correctly grouping the records for "id1" and "jobID".


For the sample data the following works

WITH
LatestStart AS (
  SELECT
    MAX(TIMESTAMP_for_start_message) TIMESTAMP_for_start_message
  FROM StartMessageTable
  GROUP BY (TRUNC(TIMESTAMP_for_start_message, 'MI'))
),
LatestStartEarliestSuccess AS (
  SELECT
    LS.TIMESTAMP_for_start_message
    , (SELECT MIN(TIMESTAMP_success_msg_received)
       FROM SuccessMessageTable
       WHERE
         (id1 = StMT.id1)
         AND (someDate = StMT.someDate)
         AND (jobID = StMT.jobID)
         AND (TIMESTAMP_success_msg_received >= StMT.TIMESTAMP_for_start_message)) TIMESTAMP_for_success_message
  FROM LatestStart LS
  JOIN StartMessageTable StMT
    ON LS.TIMESTAMP_for_start_message = StMT.TIMESTAMP_for_start_message
),
Detail AS (
  SELECT
    StMT.id1
    , LSES.TIMESTAMP_for_start_message
    , LSES.TIMESTAMP_for_success_message
    , StMT.jobID
    , 'start' msgStart
    , 'success' msgSuccess
    , StMT.time_in_seconds start_secs
    , SuMT.time_in_seconds success_secs
  FROM LatestStartEarliestSuccess LSES
  JOIN StartMessageTable StMT
    ON LSES.TIMESTAMP_for_start_message = StMT.TIMESTAMP_for_start_message
  LEFT JOIN SuccessMessageTable SuMT
    ON LSES.TIMESTAMP_for_success_message = SuMT.TIMESTAMP_success_msg_received
  ORDER BY LSES.TIMESTAMP_for_start_message
)
SELECT
  * FROM Detail
;

except for the first and last value in the "start_secs" column - which, however, seem to deviate from the sample input.
SQL Fiddle


Edit: IIF the respective "timestamp" and "second" values do -across tables- correctly reference points in time for combinations of "id1" and "jobID", the following provides an alternative starting point:

SELECT DISTINCT
  id1
  , jobID
  , message
--  , TO_CHAR(TIMESTAMP_for_start_message, 'YYYY-MM-DD HH24:MI:SS') timestamp
  , TO_CHAR(TIMESTAMP_for_start_message - NUMTODSINTERVAL(time_in_seconds, 'SECOND'), 'YYYY-MM-DD HH24:MI:SS') job_start_time
--  , time_in_seconds
FROM StartMessageTable
UNION ALL
SELECT DISTINCT
  id1
  , jobID
  , message
--  , TO_CHAR(TIMESTAMP_success_msg_received, 'YYYY-MM-DD HH24:MI:SS') timestamp
  , TO_CHAR(TIMESTAMP_success_msg_received - NUMTODSINTERVAL(time_in_seconds, 'SECOND'), 'YYYY-MM-DD HH24:MI:SS') job_start_time
--  , time_in_seconds
FROM SuccessMessageTable
ORDER BY id1, jobID, 4, message;

However, with the LEAD approach (given in another answer to this question) returning the wanted, it's probably not worth to look further into that option.



来源:https://stackoverflow.com/questions/27828293/oracle-sql-min-and-max-combination-from-same-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!