Reputation: 33
I have an oracle database table that contains test result records. Each record contains the test START_TIME, the INSTRUMENT that the test was performed on, and an ERROR_CODE if an error occurred during the test, among other information.
For every record with an ERROR_CODE equal to '5900', '6900' or '5905', I need to determine the number of successful tests (ERROR_CODE = null) that have occurred on that INSTRUMENT before the datetime of the error record. In other words, I need to know the number of successful tests performed on the instrument before an error was generated.
The database contains over 500 instruments that can each have between 1 and 500,000 test records.
Notes: Only interested in number of successes before ERROR_CODES '5900', '6000' and '5905'. Some instruments may have zero of those errors. Some instruments may have multiple consecutive errors, with no success between them. An error may have occurred on that instrument's first or last test.
Example:
START_TIME INSTRUMENT ERROR_CODE
12/1/2015 22:15:03 A540 null
12/1/2015 22:17:14 A700 null
12/1/2015 22:17:53 A700 null
12/1/2015 22:19:24 A700 5905
12/1/2015 23:28:15 A700 null
12/1/2015 23:35:10 A540 6000
12/2/2015 02:15:13 A540 5900
12/2/2015 03:07:03 A540 null
12/2/2015 03:44:52 A540 null
12/2/2015 09:15:56 A700 null
12/2/2015 14:17:09 A700 5900
12/2/2015 17:15:42 A980 null
12/3/2015 08:17:53 A540 5900
12/3/2015 08:18:49 A540 5900
12/3/2015 11:17:57 A540 null
should give the following results
ERROR_TIME INSTRUMENT SUCCESSES_BEFORE_ERROR
12/1/2015 22:19:24 A700 2
12/1/2015 23:35:10 A540 1
12/2/2015 02:15:13 A540 1
12/2/2015 14:17:09 A700 4
12/3/2015 08:17:53 A540 3
12/3/2015 08:18:49 A540 3
Upvotes: 3
Views: 490
Reputation: 1270593
There may be a way to do this with analytic functions (no doubt there is). But the simplest way to express the logic -- in my opinion -- is to use a correlated subquery:
select t.*,
(select count(*)
from t t2
where t2.instrument = t.instrument and
t2.start_time < t.start_time and
t2.error_code is null
) as SUCCESSES_BEFORE_ERROR
from t
where t.error_code is not null;
Upvotes: 0
Reputation: 1997
I dont know source table name I call it table_one
.
EDIT: As I see now I make a mistake I calculate cosequece of successfull test. I leave it as is
ordered_tab as (
select START_TIME
,INSTRUMENT
,ERROR_CODE
,row_number() over (partition by INSTRUMENT order by START_TIME) rn
from table_one)
select START_TIME as ERROR_TIME
,INSTRUMENT
,SUCCESSES_BEFORE_ERROR
FROM (
select START_TIME
,INSTRUMENT
,ERROR_CODE
,rn -1
- nvl(last_value(nvl2(ERROR_CODE,rn,null) ignore nulls)
over (partition by INSTRUMENT order by START_TIME rows between unbounded preceding and 1 preceding),0) as SUCCESSES_BEFORE_ERROR
from ordered_tab
) where ERROR_CODE IN (5905, 5900, 6000)
Upvotes: 0
Reputation: 23588
Here's a way using analytic functions:
WITH test_results AS (SELECT to_date('12/01/2015 22:15:03', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A540' instrument, NULL ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/01/2015 22:17:14', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A700' instrument, NULL ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/01/2015 22:17:53', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A700' instrument, NULL ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/01/2015 22:19:24', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A700' instrument, 5905 ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/01/2015 23:28:15', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A700' instrument, NULL ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/01/2015 23:35:10', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A540' instrument, 6000 ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/02/2015 02:15:13', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A540' instrument, 5900 ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/02/2015 03:07:03', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A540' instrument, NULL ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/02/2015 03:44:52', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A540' instrument, NULL ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/02/2015 09:15:56', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A700' instrument, NULL ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/02/2015 14:17:09', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A700' instrument, 5900 ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/02/2015 17:15:42', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A980' instrument, NULL ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/03/2015 08:17:53', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A540' instrument, 5900 ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/03/2015 08:18:49', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A540' instrument, 5900 ERROR_CODE FROM dual UNION ALL
SELECT to_date('12/03/2015 11:17:57', 'mm/dd/yyyy hh24:mi:ss') start_time, 'A540' instrument, NULL ERROR_CODE FROM dual)
-- end of mimicking a table with data in it called "test_results"
-- for use in the following select statement:
SELECT start_time,
instrument,
running_total success_before_error
FROM (SELECT start_time,
instrument,
ERROR_CODE,
sum(CASE WHEN ERROR_CODE IS NOT NULL THEN 0
ELSE 1
END) OVER (PARTITION BY instrument ORDER BY start_time) running_total
FROM test_results)
WHERE ERROR_CODE IS NOT NULL -- this may need to be "error_code in (5900, 6000, 5905)"
ORDER BY start_time;
START_TIME INSTRUMENT SUCCESS_BEFORE_ERROR
------------------- ---------- --------------------
12/01/2015 22:19:24 A700 2
12/01/2015 23:35:10 A540 1
12/02/2015 02:15:13 A540 1
12/02/2015 14:17:09 A700 4
12/03/2015 08:17:53 A540 3
12/03/2015 08:18:49 A540 3
Upvotes: 2