I have been struggling to merge datetime ranges in oracle SQL or PL/SQL (Database Standard Edition 11gR2).
I am trying to merge datetime ranges so that the following data
order_id start_date_time end_date_time
3933 04/02/2020 08:00:00 04/02/2020 12:00:00
3933 04/02/2020 13:30:00 04/02/2020 17:00:00
3933 04/02/2020 14:00:00 04/02/2020 19:00:00
3933 05/02/2020 13:40:12 05/02/2020 14:34:48
3933 05/02/2020 14:00:00 05/02/2020 18:55:12
3933 05/02/2020 14:49:48 05/02/2020 15:04:48
3933 06/02/2020 08:00:00 06/02/2020 12:00:00
3933 06/02/2020 13:30:00 06/02/2020 17:00:00
3933 06/02/2020 14:10:12 06/02/2020 18:49:48
3933 07/02/2020 08:00:00 07/02/2020 10:30:00
3933 07/02/2020 08:00:00 07/02/2020 12:00:00
3933 07/02/2020 13:30:00 07/02/2020 17:00:00
11919 14/05/2020 09:00:00 14/05/2020 17:00:00
11919 14/05/2020 09:00:00 14/05/2020 17:00:00
11919 14/05/2020 15:00:00 14/05/2020 16:30:00
11919 15/05/2020 08:40:12 15/05/2020 16:30:00
11919 15/05/2020 09:40:12 15/05/2020 16:30:00
11919 15/05/2020 10:15:00 15/05/2020 12:15:00
11919 15/05/2020 13:19:48 15/05/2020 16:00:00
11919 18/05/2020 08:49:48 18/05/2020 09:45:00
11919 18/05/2020 10:00:00 18/05/2020 17:00:00
11919 18/05/2020 10:00:00 18/05/2020 16:58:12
11919 18/05/2020 15:34:48 18/05/2020 16:10:12
11919 18/05/2020 16:30:00 18/05/2020 16:45:00
... ... ...
would transform into the following result set
--after merge (this is the result I am seeking)
order_id start_date_time end_date_time
3933 04/02/2020 08:00:00 04/02/2020 12:00:00
3933 04/02/2020 13:30:00 04/02/2020 19:00:00
3933 05/02/2020 13:40:12 05/02/2020 18:55:12
3933 06/02/2020 08:00:00 06/02/2020 12:00:00
3933 06/02/2020 13:30:00 06/02/2020 18:49:48
3933 07/02/2020 08:00:00 07/02/2020 12:00:00
3933 07/02/2020 13:30:00 07/02/2020 17:00:00
11919 14/05/2020 09:00:00 14/05/2020 17:00:00
11919 15/05/2020 08:40:12 15/05/2020 16:30:00
11919 18/05/2020 08:49:48 18/05/2020 17:00:00
... ... ...
The format of start_date_time and end_date_time is DAY/MONTH/YEAR HH24:MI:SS.
Any suggestion/solution on how to make that merge in Oracle SQL or PL/SQL?
I thought that was a trivial problem, however I was not able to find a solution on the internet yet.
Thanks in advance.
This is adapted from this answer which contains an explanation of the code. All that has changed is to add PARTITION BY order_id to calculate the date ranges for each order_id and then to return the ranges (rather than total the values, as per the linked answer):
SELECT order_id,
start_date_time,
end_date_time
FROM (
SELECT order_id,
LAG( dt ) OVER ( PARTITION BY order_id ORDER BY dt ) AS start_date_time,
dt AS end_date_time,
start_end
FROM (
SELECT order_id,
dt,
CASE SUM( value ) OVER ( PARTITION BY order_id ORDER BY dt ASC, value DESC, ROWNUM ) * value
WHEN 1 THEN 'start'
WHEN 0 THEN 'end'
END AS start_end
FROM table_name
UNPIVOT ( dt FOR value IN ( start_date_time AS 1, end_date_time AS -1 ) )
)
WHERE start_end IS NOT NULL
)
WHERE start_end = 'end';
From Oracle 12, you can use MATCH_RECONIZE to do row-by-row processing:
SELECT *
FROM table_name
MATCH_RECOGNIZE(
PARTITION BY order_id
ORDER BY start_date_time
MEASURES
FIRST(start_date_time) AS start_date_time,
MAX(end_date_time) AS end_date_time
ONE ROW PER MATCH
PATTERN (overlapping_rows* last_row)
DEFINE
overlapping_rows AS NEXT(start_date_time) <= MAX(end_date_time)
)
Which, for your test data:
CREATE TABLE table_name (
order_id NUMBER,
start_date_time DATE,
end_date_time DATE
);
INSERT INTO table_name ( order_id, start_date_time, end_date_time )
SELECT 3933, TIMESTAMP '2020-02-04 08:00:00', TIMESTAMP '2020-02-04 12:00:00' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-04 13:30:00', TIMESTAMP '2020-02-04 17:00:00' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-04 14:00:00', TIMESTAMP '2020-02-04 19:00:00' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-05 13:40:12', TIMESTAMP '2020-02-05 14:34:48' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-05 14:00:00', TIMESTAMP '2020-02-05 18:55:12' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-05 14:49:48', TIMESTAMP '2020-02-05 15:04:48' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-06 08:00:00', TIMESTAMP '2020-02-06 12:00:00' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-06 13:30:00', TIMESTAMP '2020-02-06 17:00:00' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-06 14:10:12', TIMESTAMP '2020-02-06 18:49:48' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-07 08:00:00', TIMESTAMP '2020-02-07 10:30:00' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-07 08:00:00', TIMESTAMP '2020-02-07 12:00:00' FROM DUAL UNION ALL
SELECT 3933, TIMESTAMP '2020-02-07 13:30:00', TIMESTAMP '2020-02-07 17:00:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-14 09:00:00', TIMESTAMP '2020-05-14 17:00:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-14 09:00:00', TIMESTAMP '2020-05-14 17:00:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-14 15:00:00', TIMESTAMP '2020-05-14 16:30:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-15 08:40:12', TIMESTAMP '2020-05-15 16:30:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-15 09:40:12', TIMESTAMP '2020-05-15 16:30:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-15 10:15:00', TIMESTAMP '2020-05-15 12:15:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-15 13:19:48', TIMESTAMP '2020-05-15 16:00:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-18 08:49:48', TIMESTAMP '2020-05-18 09:45:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-18 10:00:00', TIMESTAMP '2020-05-18 17:00:00' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-18 10:00:00', TIMESTAMP '2020-05-18 16:58:12' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-18 15:34:48', TIMESTAMP '2020-05-18 16:10:12' FROM DUAL UNION ALL
SELECT 11919, TIMESTAMP '2020-05-18 16:30:00', TIMESTAMP '2020-05-18 16:45:00' FROM DUAL;
Which both output:
ORDER_ID | START_DATE_TIME | END_DATE_TIME
-------: | :------------------ | :------------------
3933 | 2020-02-04 08:00:00 | 2020-02-04 12:00:00
3933 | 2020-02-04 13:30:00 | 2020-02-04 19:00:00
3933 | 2020-02-05 13:40:12 | 2020-02-05 18:55:12
3933 | 2020-02-06 08:00:00 | 2020-02-06 12:00:00
3933 | 2020-02-06 13:30:00 | 2020-02-06 18:49:48
3933 | 2020-02-07 08:00:00 | 2020-02-07 12:00:00
3933 | 2020-02-07 13:30:00 | 2020-02-07 17:00:00
11919 | 2020-05-14 09:00:00 | 2020-05-14 17:00:00
11919 | 2020-05-15 08:40:12 | 2020-05-15 16:30:00
11919 | 2020-05-18 08:49:48 | 2020-05-18 09:45:00
11919 | 2020-05-18 10:00:00 | 2020-05-18 17:00:00
db<>fiddle here
The solution below uses a common method known as the "start of group" method.
The idea is to order the intervals by start date (separately for each id), and to assign intervals to groups as follows. For each interval, check if its start time is strictly greater than the MAX of end times of all preceding intervals. If it is, that starts a new group. The rest is easy - just select the MIN start date and the MAX end date from each group.
Here is how this is implemented, using analytic functions:
with
has_sog_flags (order_id, start_date_time, end_date_time, flag) as (
select order_id, start_date_time, end_date_time,
case when start_date_time >
max(end_date_time) over (partition by order_id
order by start_date_time
rows between unbounded preceding and 1 preceding)
then 1 end
from table_name
)
, has_groups (order_id, start_date_time, end_date_time, grp) as (
select order_id, start_date_time, end_date_time,
sum(flag) over (partition by order_id order by start_date_time)
from has_sog_flags
)
select order_id, min(start_date_time) as start_date_time,
max(end_date_time) as end_date_time
from has_groups
group by order_id, grp
order by order_id, start_date_time
;
An interesting question is how to handle open-ended intervals (where for example null for end_date_time means "open ended into the future". The query can be adapted relatively easily to cover such extensions to the problem statement.
This is how I solved. Imagine an ORDERS table with ORDERID, DATE_START and DATE_END. The innermost query (A) gets the previous end date, the second innermost subquery (B) detects overlaps (or better nooverlaps), the third sums nooverlap to create groups (GID). Finally the outermost query aggregates these groups to create the final intervals for each ORDERID.
SELECT C.ORDERID, MIN(C.DATE_START ) DATE_START , MAX(C.DATE_END) DATE_END
FROM
(
SELECT B.*,SUM(B.NOOVERLAP) over(PARTITION BY B.ORDERID order by B.DATE_START ) as GID
FROM
(
SELECT A.*,
CASE WHEN A.PREV_DATE_END >= A.DATE_START THEN 0 ELSE 1 END NOOVERLAP
FROM
(
SELECT ORDERID,DATE_START ,DATE_END,
LAG(DATE_END) OVER(PARTITION BY ORDERID ORDER BY DATE_START ) PREV_DATE_END
FROM ORDERS
) A
) B
) C
GROUP BY C.ORDERID , C.GID
Related
I have a table called b_hearings. I have two date columns: hearingdt and hearingtm. Hearingdt has the correct date and hearingtm has the correct time. I need to merge or update so they appear together.
hearingdt | hearingtm
---------------------------------------
2019-02-13 00:00:00 1899-12-30 14:30:00
2014-06-10 00:00:00 1899-12-30 09:00:00
2017-08-01 00:00:00 1899-12-30 09:30:00
2014-08-04 00:00:00 1899-12-30 09:00:00
What is the best approach? Should I add the time from hearingtm and put it in hearingdt? Should I create a new column and add the data there. I'm not sure how to split dates. Here is the result I'm looking for:
hearingdt
-------------------
2019-02-13 14:30:00
2014-06-10 09:00:00
2017-08-01 09:30:00
2014-08-04 09:00:00
Many thanks in advance for your help!
You should store the values in a single column. To convert, you can use:
select to_date( (to_char(hearingdt, 'YYYY-MM-DD') ||
' ' ||
to_char(hearingtm, 'HH24:MI:SS')
), 'YYYY-MM-DD HH24:MI:SS'
)
You can do this in an update. Or as a computed column.
You can add the time component of hearingtm to hearingdt:
UPDATE b_hearings
SET hearingdt = TRUNC( hearingdt )
+ ( hearingtm - TRUNC( hearingtm ) ) DAY TO SECOND
Then you can drop the hearingtm column:
ALTER TABLE b_hearings DROP COLUMN hearingtm;
Which, for your test data:
CREATE TABLE b_hearings (
hearingdt DATE,
hearingtm DATE
);
INSERT INTO b_hearings ( hearingdt, hearingtm )
SELECT TIMESTAMP '2019-02-13 00:00:00', TIMESTAMP '1899-12-30 14:30:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2014-06-10 00:00:00', TIMESTAMP '1899-12-30 09:00:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-08-01 00:00:00', TIMESTAMP '1899-12-30 09:30:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2014-08-04 00:00:00', TIMESTAMP '1899-12-30 09:00:00' FROM DUAL
Would give you:
SELECT * FROM b_hearings;
| HEARINGDT |
| :------------------ |
| 2019-02-13 14:30:00 |
| 2014-06-10 09:00:00 |
| 2017-08-01 09:30:00 |
| 2014-08-04 09:00:00 |
db<>fiddle here
So I'm trying to select the distinct operators from a table with a time component that is formatted like this: 'MM/DD/YYYY HH:MI:SS AM.'
The logic is this:
(if C_StartTime >= date(C_StartTime) + 6:00:00 AM
AND C_StartTime < date(C_StartTime) + 5:59:59AM
then C_StartTime,'MM/DD/YYYY'
ELSE (C_StartTime,'MM/DD/YYYY')-1)
AS DateOnly
I can select distinct operators right now but they sign in and out a few times a day so the time is different. It should be noted that "Today" at this company is 3/13/19 6:00:00 AM to 3/14/19 5:59:59 AM.
Below is the final code I tried executing
SELECT
DISTINCT (
(
CASE WHEN C_StartTime >= date(C_StartTime) +.25
AND C_StartTime < date(C_StartTime) +.9999
THEN date(C_StartTime)
ELSE date(C_StartTime) -1
) as DateOnly,
C_operator,
C_operatorname,
C_WorkCentreName
FROM
OPERATORTABLE
WHERE
.....
EDIT>>>>>>
This is what I get.
This is what I need
I'm Looking for the operator number, the operator name, and the date only (with the knowledge that 1/4/2019 5:59:00 AM = 1/3/2019
I think you're probably after something like trunc(c_starttime - 6/24) + 6/24 to get the day to start at 6am instead of midnight:
WITH dts AS (SELECT to_date('13/03/2019 05:59:59', 'dd/mm/yyyy hh24:mi:ss') dt FROM dual UNION ALL
SELECT to_date('13/03/2019 06:00:00', 'dd/mm/yyyy hh24:mi:ss') dt FROM dual UNION ALL
SELECT to_date('13/03/2019 06:00:01', 'dd/mm/yyyy hh24:mi:ss') dt FROM dual UNION ALL
SELECT to_date('14/03/2019 05:59:59', 'dd/mm/yyyy hh24:mi:ss') dt FROM dual UNION ALL
SELECT to_date('14/03/2019 06:00:00', 'dd/mm/yyyy hh24:mi:ss') dt FROM dual)
SELECT dt,
dt - 6/24 adj_dt,
TRUNC(dt - 6/24) trunc_adj_dt,
TRUNC(dt - 6/24) + 6/24 adj_start_of_dt
FROM dts;
DT ADJ_DT TRUNC_ADJ_DT ADJ_START_OF_DT
------------------- ------------------- ------------------- -------------------
13/03/2019 05:59:59 12/03/2019 23:59:59 12/03/2019 00:00:00 12/03/2019 06:00:00
13/03/2019 06:00:00 13/03/2019 00:00:00 13/03/2019 00:00:00 13/03/2019 06:00:00
13/03/2019 06:00:01 13/03/2019 00:00:01 13/03/2019 00:00:00 13/03/2019 06:00:00
14/03/2019 05:59:59 13/03/2019 23:59:59 13/03/2019 00:00:00 13/03/2019 06:00:00
14/03/2019 06:00:00 14/03/2019 00:00:00 14/03/2019 00:00:00 14/03/2019 06:00:00
I've selected the adj_dt and trunc_adj_dt columns so that you can see how the adj_start_of_dt column was calculated from the original dt column.
You may not need to output 6am on the start date column, so you can skip that (i.e. it's trunc_adj_dt that is the column you'd be after in that case).
So, i have this sample data:
Department | InitialDate | FinalDate
-------------------------------------------------------
1 | 01/01/2017 01:12:00 | 01/03/2017 00:00:08
1 | 01/03/2017 00:00:08 | 01/04/2017 05:00:01
1 | 01/04/2017 05:00:01 | 01/05/2017 02:00:00
2 | 01/05/2017 10:00:00 | 01/06/2017 11:00:08
2 | 01/06/2017 11:00:08 | 01/07/2017 04:04:00
3 | 01/07/2017 04:00:00 | 01/07/2017 15:00:22
1 | 01/07/2017 14:00:00 | 01/07/2017 18:00:08
1 | 01/07/2017 18:15:00 | 01/08/2017 22:00:00
3 | 01/12/2017 01:30:03 | 01/12/2017 18:00:00
1 | 01/13/2017 23:12:00 | 01/13/2017 23:59:08
and want to group it like this
Department | InitialDate | FinalDate
-------------------------------------------------------
1 | 01/01/2017 01:12:00 | 01/05/2017 02:00:00
2 | 01/05/2017 10:00:00 | 01/07/2017 04:04:00
3 | 01/07/2017 04:00:00 | 01/07/2017 15:00:22
1 | 01/07/2017 14:00:00 | 01/08/2017 22:00:00
3 | 01/12/2017 01:30:03 | 01/12/2017 18:00:00
1 | 01/13/2017 23:12:00 | 01/13/2017 23:59:08
I need to make groups by department and get the first and last date of each group, but the departments can repeat and for each time it occurs, I want the first and last date of that specific window. I already tried Analytic functions but nothing seems to work.
You can do it using the LAG analytic function to compare each row with the previous row:
SELECT department,
MIN( InitialDate ) AS InitialDate,
MIN( FinalDate ) AS FinalDate
FROM (
SELECT department,
InitialDate,
FinalDate,
SUM( grp_inc ) OVER ( ORDER BY FinalDate ) AS grp
FROM (
SELECT department,
InitialDate,
FinalDate,
CASE WHEN LAG( department ) OVER ( ORDER BY FinalDate ) = department
THEN 0
ELSE 1
END AS grp_inc
FROM table_name
)
)
GROUP BY department, grp
This is a type of "gaps-and-islands" problem. One method of solving it is by determining where groups of overlapping times start. Then use a cumulative sum to define each group:
select departmentid, min(initialdate), max(finaldate)
from (select t.*, sum(grp_starts) over (partition by departmentid order by initialdate) as grp
from (select t.*,
(case when exists (select 1
from t t2
where t2.departmentid = t.departmentid and
t.initialdate > t2.initialdate and
t.initialdate <= t2.finaldate
)
then 0 else 1
end) as grp_starts
from t
) t
) t
group by departmentid, grp;
Since you are looking for where the department changes and not where the department changes or the initialdate is not the same as the previous row's finaldate, you can use tabibitosan
WITH sample_data AS (SELECT 1 department, to_date('01/01/2017 01:12:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/03/2017 00:00:08', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 1 department, to_date('01/03/2017 00:00:08', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/04/2017 05:00:01', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 1 department, to_date('01/04/2017 05:00:01', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/05/2017 02:00:00', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 2 department, to_date('01/05/2017 10:00:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/06/2017 11:00:08', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 2 department, to_date('01/06/2017 11:00:08', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/07/2017 04:04:00', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 3 department, to_date('01/07/2017 04:00:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/07/2017 15:00:22', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 1 department, to_date('01/07/2017 14:00:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/07/2017 18:00:08', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 1 department, to_date('01/07/2017 18:15:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/08/2017 22:00:00', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 3 department, to_date('01/12/2017 01:30:03', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/12/2017 18:00:00', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
SELECT 1 department, to_date('01/13/2017 23:12:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/13/2017 23:59:08', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual)
SELECT department,
MIN(initialdate) initialdate,
MAX(finaldate) finaldate
FROM (SELECT department,
initialdate,
finaldate,
row_number() OVER (ORDER BY initialdate)
- row_number() OVER (PARTITION BY department ORDER BY initialdate) grp
FROM sample_data sd)
GROUP BY department, grp
ORDER BY initialdate;
DEPARTMENT INITIALDATE FINALDATE
---------- ------------------- -------------------
1 01/01/2017 01:12:00 01/05/2017 02:00:00
2 01/05/2017 10:00:00 01/07/2017 04:04:00
3 01/07/2017 04:00:00 01/07/2017 15:00:22
1 01/07/2017 14:00:00 01/08/2017 22:00:00
3 01/12/2017 01:30:03 01/12/2017 18:00:00
1 01/13/2017 23:12:00 01/13/2017 23:59:08
This works by walking through and numbering all rows ordered by initial date and comparing them to walking through and numbering the rows for each department. When the department changes, the difference between the numbers changes. Where a department has consecutive rows in the initial dataset, the difference will remain the same for those rows. E.g. in your data, department 1 has 6 rows, the first 3 rows are the same as the first 3 rows of the initial data set, so the difference for those three rows is 0. The fourth and fifth department 1 rows are the 7th and 8th rows in the dataset, so the difference is 3 for those rows, etc.
This gives us a number that we can use, in conjunction with the department number, to group the data by. It's then a simple matter of finding the min/max dates within that group.
I have table with column Date with timestamp, value in seconds and have query like
Table
2017-01-10 06:45:00 PM 1119
2017-01-10 03:30:00 PM 1054
2017-01-11 11:15:00 PM 379
2017-01-10 06:30:00 PM 377
2017-01-11 09:15:00 PM 375
Query
SELECT
TO_char(DtTm,'YYYY-MM-DD hh:mi:ss AM') As DataDt,
max(MaxSec) as Wait_sec, DtTimeTable.HrID,
FROM DtTimeTable
WHERE DtTimeTable.HrName in ('Dept1', 'Dept2', 'Dept3')
AND DtTm BETWEEN to_date('2017-01-08 00:00:00', 'YYYY-MM-DD hh24:mi:ss')
AND to_date('2017-01-10 23:59:59', 'YYYY-MM-DD hh24:mi:ss')
Group by TO_char(DtTm,'YYYY-MM-DD hh:mi:ss AM'),DtTimeTable.HrID
order by Wait_sec desc
This gives me All records and if i add
select * from
Query1 --(above)
where rownum <1 order by Wait_sec desc, Datadt desc;
I am only getting highest value of result set
How can get DatewithTime, Maxvalue for each date like
2017-01-10 06:45:00 PM 1119
2017-01-11 11:15:00 PM 379
Try something like this:
Select *
From (
Select t.*,
Row_number() over(partition by trunc(datecol) order by value desc nulls last) rn
From yourtable t
) where rn = 1;
It assign row number within date based on descending order your value column and then filters to get the first row
The solution below uses grouping, the MAX() aggregate function, and the FIRST/LAST function (with KEEP DENSE_RANK). If for a date the same highest value is reached more than once, it picks the first time during the day that the value was reached.
with
test_data( dt, val ) as (
select to_date('2017-01-10 06:45:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 1119 from dual
union all
select to_date('2017-01-10 03:30:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 1054 from dual
union all
select to_date('2017-01-11 11:15:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 379 from dual
union all
select to_date('2017-01-10 06:30:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 377 from dual
union all
select to_date('2017-01-11 09:15:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 375 from dual
)
-- end of test data; SQL query begins below this line (use actual table and column names)
select min(dt) keep(dense_rank last order by val) as dt, max(val) as val
from test_data
group by trunc(dt)
order by dt -- if needed
;
DT VAL
---------------------- ----------
2017-01-10 06:45:00 PM 1119
2017-01-11 11:15:00 PM 379
2 rows selected.
I have a data set which is based on a timestamp. The Data set present record on every shut down occurrence in a 5 minute time interval. If a shut down occurred in the specific 5 min, then the record is added else no record. Thus no record means system has recovered
Date
07-Jul-15 12:05:00
07-Jul-15 12:10:00
07-Jul-15 12:15:00
07-Jul-15 12:35:00
07-Jul-15 12:40:00
07-Jul-15 12:45:00
07-Jul-15 12:50:00
07-Jul-15 13:05:00
07-Jul-15 13:10:00
07-Jul-15 13:15:00
I would like to query and return
1.Number of shutdowns: The Number of shut down in this case is 3 based on between
12:15 to 12:35
12:50 to 13:05
The system recovered
Period Between every shut down
Example:
1.From: 07-Jul-15 12:05:00 To: 07-Jul-15 12:15:00 Duration : 15 Mins
2.From: 07-Jul-15 12:35:00 To: 07-Jul-15 12:50:00 Duration : 20 Mins
There is a similar Question although a very different solution is required for this one.
would appreciate a fiddle example
WITH changes AS (
SELECT "DATE",
CASE WHEN LAG( "DATE" ) OVER ( ORDER BY "DATE" ) + INTERVAL '5' MINUTE = "DATE" THEN 0 ELSE 1 END AS has_changed_group
FROM TEST
), grps AS (
SELECT "DATE",
SUM( has_changed_group ) OVER ( ORDER BY "DATE" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS grp
FROM changes
)
SELECT MIN( "DATE" ) AS shutdown_start,
MAX( "DATE" ) AS shutdown_end,
MAX( "DATE" ) - MIN( "DATE" ) + INTERVAL '5' MINUTE AS shutdown_duration
FROM grps
GROUP BY grp;
Output:
SHUTDOWN_START SHUTDOWN_END SHUTDOWN_DURATION
---------------------------- ---------------------------- -----------------
07-JUL-15 12.05.00.000000000 07-JUL-15 12.15.00.000000000 0 0:15:0.0
07-JUL-15 12.35.00.000000000 07-JUL-15 12.50.00.000000000 0 0:20:0.0
07-JUL-15 13.05.00.000000000 07-JUL-15 13.15.00.000000000 0 0:15:0.0
Edit - Multiple machines:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TEST ( MACHINE_ID, "DATE" ) AS
SELECT 1, TIMESTAMP '2015-07-07 12:05:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 12:10:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 12:15:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 12:35:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 12:40:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 12:45:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 12:50:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 13:05:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 13:10:00' FROM DUAL
UNION ALL SELECT 1, TIMESTAMP '2015-07-07 13:15:00' FROM DUAL
UNION ALL SELECT 2, TIMESTAMP '2015-07-07 12:35:00' FROM DUAL
UNION ALL SELECT 2, TIMESTAMP '2015-07-07 12:40:00' FROM DUAL
UNION ALL SELECT 2, TIMESTAMP '2015-07-07 12:45:00' FROM DUAL
UNION ALL SELECT 2, TIMESTAMP '2015-07-07 13:00:00' FROM DUAL
UNION ALL SELECT 2, TIMESTAMP '2015-07-07 13:05:00' FROM DUAL
UNION ALL SELECT 2, TIMESTAMP '2015-07-07 13:10:00' FROM DUAL
UNION ALL SELECT 2, TIMESTAMP '2015-07-07 13:15:00' FROM DUAL;
Query 1:
WITH changes AS (
SELECT MACHINE_ID,
"DATE",
CASE WHEN LAG( "DATE" ) OVER ( PARTITION BY MACHINE_ID ORDER BY "DATE" ) + INTERVAL '5' MINUTE = "DATE" THEN 0 ELSE 1 END AS has_changed_group
FROM TEST
), grps AS (
SELECT MACHINE_ID,
"DATE",
SUM( has_changed_group ) OVER ( PARTITION BY MACHINE_ID ORDER BY "DATE" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS grp
FROM changes
)
SELECT MACHINE_ID,
TO_CHAR( MIN( "DATE" ), 'YYYY-MM-DD HH24:MI:SS' ) AS shutdown_start,
TO_CHAR( MAX( "DATE" ), 'YYYY-MM-DD HH24:MI:SS' ) AS shutdown_end,
TO_CHAR( MAX( "DATE" ) - MIN( "DATE" ) + INTERVAL '5' MINUTE ) AS shutdown_duration
FROM grps
GROUP BY MACHINE_ID, grp
ORDER BY 1,2
Results:
| MACHINE_ID | SHUTDOWN_START | SHUTDOWN_END | SHUTDOWN_DURATION |
|------------|---------------------|---------------------|-------------------------------|
| 1 | 2015-07-07 12:05:00 | 2015-07-07 12:15:00 | +000000000 00:15:00.000000000 |
| 1 | 2015-07-07 12:35:00 | 2015-07-07 12:50:00 | +000000000 00:20:00.000000000 |
| 1 | 2015-07-07 13:05:00 | 2015-07-07 13:15:00 | +000000000 00:15:00.000000000 |
| 2 | 2015-07-07 12:35:00 | 2015-07-07 12:45:00 | +000000000 00:15:00.000000000 |
| 2 | 2015-07-07 13:00:00 | 2015-07-07 13:15:00 | +000000000 00:20:00.000000000 |
Solution using Tom Kyte's "carry down" technique:
with test1 as (
select mydate,
-- mark starting records in each group
case when NVL((mydate - lag(mydate) over (order by mydate))*24*60,10) > 5
then row_number() over (order by mydate) end as group_id
from test),
test2 as (
select mydate,
-- propagate group_id to all records
LAST_VALUE(group_id IGNORE NULLS) over (order by mydate) as group_id
from test1)
select min(mydate) shutdown_from, max(mydate) shutdown_to
from test2
group by group_id;
Output
SHUTDOWN_FROM SHUTDOWN_TO
------------------- -------------------
07.07.0015 12:05:00 07.07.0015 12:15:00
07.07.0015 12:35:00 07.07.0015 12:50:00
07.07.0015 13:05:00 07.07.0015 13:15:00