Reputation: 186
I have an interesting problem that I know I can solve in code, but i am thinking there must be an elegant solution using native SQL. Here is my problem...
I have a table (OP) that show all the operations that need to be performed on a part (laser, shake-out, punch, etc.) It would look something like this
Op# WorkCenter Job# Status
10 Laser 11222 C
15 Shake-Out 11222 C
20 Brake 11222 O
30 WashDown 11222 O
40 Paint 11222 O
10 Punch 11250 C
15 Shake-Out 11250 C
20 Brake 11250 O
30 WashDown 11250 O
40 Paint 11250 O
10 Laser 11260 C
15 Shake-Out 11260 C
20 Brake 11260 C
30 WashDown 11260 C
40 Paint 11260 C
10 Laser 11260 C
15 Shake-Out 11260 O
20 Brake 11260 O
30 WashDown 11260 O
40 Paint 11260 O
So what I want is to select * from OP showing the record for the NEXT workcenter AFTER Shake-Out where Shake-Out status is C and the next WC is O.
Using the above data, I would want to see the following records as my result:
Op# WorkCenter Job# Status
20 Brake 11222 O
20 Brake 11250 O
I am fairly certain I need a subquery either in the select or the from clause, but I am not sure how to do that.
Hopefully this makes sense, and someone can assist me with this query?
Thank You in advance!!
Upvotes: 0
Views: 60
Reputation: 167972
Oracle 11g R2 Schema Setup:
CREATE TABLE OP ( Op_number, WorkCenter, Job_number, Status ) AS
SELECT 10, 'Laser', 11222, 'C' FROM DUAL
UNION ALL SELECT 15, 'Shake-Out', 11222, 'C' FROM DUAL
UNION ALL SELECT 20, 'Brake', 11222, 'O' FROM DUAL
UNION ALL SELECT 30, 'WashDown', 11222, 'O' FROM DUAL
UNION ALL SELECT 40, 'Paint', 11222, 'O' FROM DUAL
UNION ALL SELECT 10, 'Punch', 11250, 'C' FROM DUAL
UNION ALL SELECT 15, 'Shake-Out', 11250, 'C' FROM DUAL
UNION ALL SELECT 20, 'Brake', 11250, 'O' FROM DUAL
UNION ALL SELECT 30, 'WashDown', 11250, 'O' FROM DUAL
UNION ALL SELECT 40, 'Paint', 11250, 'O' FROM DUAL
UNION ALL SELECT 10, 'Laser', 11260, 'C' FROM DUAL
UNION ALL SELECT 15, 'Shake-Out', 11260, 'C' FROM DUAL
UNION ALL SELECT 20, 'Brake', 11260, 'C' FROM DUAL
UNION ALL SELECT 30, 'WashDown', 11260, 'C' FROM DUAL
UNION ALL SELECT 40, 'Paint', 11260, 'C' FROM DUAL
UNION ALL SELECT 10, 'Laser', 11280, 'C' FROM DUAL
UNION ALL SELECT 15, 'Shake-Out', 11280, 'O' FROM DUAL
UNION ALL SELECT 20, 'Brake', 11280, 'O' FROM DUAL
UNION ALL SELECT 30, 'WashDown', 11280, 'O' FROM DUAL
UNION ALL SELECT 40, 'Paint', 11280, 'O' FROM DUAL;
Query 1:
SELECT Op_Number,
WorkCenter,
Job_Number,
Status
FROM (
SELECT o.*,
LAG( WorkCenter ) OVER ( PARTITION BY Job_Number ORDER BY Op_Number ) AS prev_workcenter,
LAG( Status ) OVER ( PARTITION BY Job_Number ORDER BY Op_Number ) AS prev_status
FROM OP o
)
WHERE prev_workcenter = 'Shake-Out'
AND prev_status = 'C'
AND status = 'O'
| OP_NUMBER | WORKCENTER | JOB_NUMBER | STATUS |
|-----------|------------|------------|--------|
| 20 | Brake | 11222 | O |
| 20 | Brake | 11250 | O |
Upvotes: 1
Reputation: 995
Here's an aprroximate query, unfortuantely I don't have an Oracle instance / sqlplus to test it against right now. I'll update tomorrow with a fully working question if you don't have an answer by then
select op#, row_number() over (partition by job_id, order by op#)
from (
select op#,workcenter,job#,status
from tab
where job_id = (select job_id
from tab
where status = 'C' and workcenter = 'Shake-Out')
and op# > (select op#
from tab
where status = 'C' and workcenter = 'Shake-Out')
order by job_id, op#) tab2
where status = 'O'
The idea is to get any jobs where the workcenter is shake-out with status C and get their job number. Then look for op#'s greater than that and take the next row with status 0. So you'd just pick out the rownum of 1 in a parent query to this.
PS This would be an alternative to the proposed lag or lead, the problem being you don't know how far in advance you want to go in that case.
Upvotes: 0