简体   繁体   中英

Oracle query to get subselection of data

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!!

SQL Fiddle

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'

Results :

| OP_NUMBER | WORKCENTER | JOB_NUMBER | STATUS |
|-----------|------------|------------|--------|
|        20 |      Brake |      11222 |      O |
|        20 |      Brake |      11250 |      O |

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM