Reputation: 113
I have a view with the following info:
id | contractId | opId | opStatus | opDate |
---|---|---|---|---|
1 | 2 | 201 | Done | 01/01/2024 |
2 | 2 | 202 | Processing | 01/01/2024 |
3 | 2 | 203 | Done | 01/01/2024 |
4 | 3 | 301 | Waiting | 01/01/2024 |
5 | 3 | 302 | Processing | 02/01/2024 |
6 | 4 | 401 | Waiting | 05/01/2024 |
7 | 4 | 402 | Waiting | 06/01/2024 |
8 | 5 | 501 | Done | 01/01/2024 |
What I need is to filter the data based on the next criteria:
opStatus
for any operation in contract is Done
- take all lines with this status and the same dateopStatus
for any operation in contract is Processing
- take all lines with this status and the same date (like the first criteria)opDate
So after all this steps I should have a table with a result:
id | contractId | opId | opStatus | opDate |
---|---|---|---|---|
1 | 2 | 201 | Done | 01/01/2024 |
3 | 2 | 203 | Done | 01/01/2024 |
5 | 3 | 302 | Processing | 02/01/2024 |
6 | 4 | 401 | Waiting | 05/01/2024 |
8 | 5 | 501 | Done | 01/01/2024 |
What would be a possibly required SQL? Database is Oracle.
Upvotes: 0
Views: 75
Reputation: 1075
You can use window function as follows:
Select t.* from
(Select t.*,
Count(case when opstatus = 'Done' then 1 end) over (partition by contractid) as donecnt,
Count(case when opstatus = 'Processing' then 1 end) over (partition by contractid) as processingcnt,
Row_number() over (partition by contractid order by opdate) as rn
From your_table t) t
Where (donecnt > 0 and opstatus = 'Done')
Or (processingcnt > 0 and donecnt = 0 and opstatus = 'Processing')
Or (processingcnt = 0 and donecnt = 0 and rn = 1)
order by id;
Upvotes: 1
Reputation: 168598
From Oracle 12, you can use MATCH_RECOGNIZE
for row-by-row pattern matching:
SELECT id, contractId, opId, opStatus, opDate
FROM table_name
MATCH_RECOGNIZE(
PARTITION BY contractId
ORDER BY opDate, id
ALL ROWS PER MATCH
PATTERN ( ^ ({- any_row*? -} done)+
| ^ ({- any_row*? -} processing)+
| ^ any_row
)
DEFINE
done AS opStatus = 'Done'
AND TRUNC(opDate) = TRUNC(FIRST(done.opDate)),
processing AS opStatus = 'Processing'
AND TRUNC(opDate) = TRUNC(FIRST(processing.opDate))
)
Which, for the sample data:
CREATE TABLE table_name (id, contractId, opId, opStatus, opDate) AS
SELECT 1, 2, 201, 'Done', DATE '2024-01-01' FROM DUAL UNION ALL
SELECT 2, 2, 202, 'Processing', DATE '2024-01-01' FROM DUAL UNION ALL
SELECT 3, 2, 203, 'Done', DATE '2024-01-01' FROM DUAL UNION ALL
SELECT 4, 3, 301, 'Waiting', DATE '2024-01-01' FROM DUAL UNION ALL
SELECT 5, 3, 302, 'Processing', DATE '2024-01-02' FROM DUAL UNION ALL
SELECT 6, 4, 401, 'Waiting', DATE '2024-01-05' FROM DUAL UNION ALL
SELECT 7, 4, 402, 'Waiting', DATE '2024-01-06' FROM DUAL UNION ALL
SELECT 8, 5, 501, 'Done', DATE '2024-01-01' FROM DUAL;
Outputs:
ID | CONTRACTID | OPID | OPSTATUS | OPDATE |
---|---|---|---|---|
1 | 2 | 201 | Done | 2024-01-01 00:00:00 |
3 | 2 | 203 | Done | 2024-01-01 00:00:00 |
5 | 3 | 302 | Processing | 2024-01-02 00:00:00 |
6 | 4 | 401 | Waiting | 2024-01-05 00:00:00 |
8 | 5 | 501 | Done | 2024-01-01 00:00:00 |
Upvotes: 2