Home > Blockchain >  How to select all data before current_state in history data in Oracle SQL?
How to select all data before current_state in history data in Oracle SQL?

Time:02-14

So I have data look like in Picture. Column name Track is to show the step of the state. Column name Current_state is the status of the app right now. Column name Current_state_hist is the history of the status.

So right now the current status now is AP. I want to Select all the status before the last status right now (AP in Track 13 & 14) without remove the status AP in track 5 - 8.

Can somebody help me for this case? Thank you Example of the data

CodePudding user response:

You can use EXISTS for that:

Schema and insert statements:

 create table table1(id int, track int, current_state varchar(10), current_state_hist varchar(10), total_unit int);


 insert into table1 values(1,1,'AP','OD',1)
 insert into table1 values(1,2,'AP','OD',1)
 insert into table1 values(1,3,'AP','OD',1)
 insert into table1 values(1,4,'AP','OD',1)
 insert into table1 values(1,5,'AP','AP',1)
 insert into table1 values(1,6,'AP','AP',1)
 insert into table1 values(1,7,'AP','AP',1)
 insert into table1 values(1,8,'AP','AP',1)
 insert into table1 values(1,9,'AP','OD',1)
 insert into table1 values(1,10,'AP','OD',1)
 insert into table1 values(1,11,'AP','OD',1)
 insert into table1 values(1,12,'AP','OD',1)
 insert into table1 values(1,13,'AP','AP',1)
 insert into table1 values(1,14,'AP','AP',1)

Query:

 SELECT ID,TRACK,CURRENT_STATE,CURRENT_STATE_HIST,TOTAL_UNIT
 FROM TABLE1  T1 
 WHERE EXISTS
            (
                SELECT 1 FROM TABLE1 T2 
                WHERE CURRENT_STATE<>CURRENT_STATE_HIST 
                AND T1.TRACK<=T2.TRACK
            )

Output:

ID TRACK CURRENT_STATE CURRENT_STATE_HIST TOTAL_UNIT
1 1 AP OD 1
1 2 AP OD 1
1 3 AP OD 1
1 4 AP OD 1
1 5 AP AP 1
1 6 AP AP 1
1 7 AP AP 1
1 8 AP AP 1
1 9 AP OD 1
1 10 AP OD 1
1 11 AP OD 1
1 12 AP OD 1

db<>fiddle here

CodePudding user response:

You can find the latest status without having to query the table twice using the ROW_NUMBER analytic function:

SELECT id, track, current_state, current_state_hist, total_unit
FROM   (
  SELECT t.*,
         ROW_NUMBER() OVER (ORDER BY track DESC)
           - ROW_NUMBER() OVER (
               PARTITION BY current_state_hist ORDER BY track DESC
             ) AS rn
  FROM   table_name t
)
WHERE rn > 0;

Or, from Oracle 12:

SELECT *
FROM   table_name
MATCH_RECOGNIZE(
  ORDER BY track DESC
  ALL ROWS PER MATCH
  PATTERN ( ^ {- same_hist  -} any_hist* )
  DEFINE
    same_hist AS FIRST(current_state_hist) = current_state_hist
)

Which, for the sample data:

CREATE TABLE table_name (id, track, current_state, current_state_hist, total_unit) AS
SELECT 1,  1, 'AP', 'OD', 1 FROM DUAL UNION ALL
SELECT 1,  2, 'AP', 'OD', 1 FROM DUAL UNION ALL
SELECT 1,  3, 'AP', 'OD', 1 FROM DUAL UNION ALL
SELECT 1,  4, 'AP', 'OD', 1 FROM DUAL UNION ALL
SELECT 1,  5, 'AP', 'AP', 1 FROM DUAL UNION ALL
SELECT 1,  6, 'AP', 'AP', 1 FROM DUAL UNION ALL
SELECT 1,  7, 'AP', 'AP', 1 FROM DUAL UNION ALL
SELECT 1,  8, 'AP', 'AP', 1 FROM DUAL UNION ALL
SELECT 1,  9, 'AP', 'OD', 1 FROM DUAL UNION ALL
SELECT 1, 10, 'AP', 'OD', 1 FROM DUAL UNION ALL
SELECT 1, 11, 'AP', 'OD', 1 FROM DUAL UNION ALL
SELECT 1, 12, 'AP', 'OD', 1 FROM DUAL UNION ALL
SELECT 1, 13, 'AP', 'AP', 1 FROM DUAL UNION ALL
SELECT 1, 14, 'AP', 'AP', 1 FROM DUAL;

Both output:

ID TRACK CURRENT_STATE CURRENT_STATE_HIST TOTAL_UNIT
1 12 AP OD 1
1 11 AP OD 1
1 10 AP OD 1
1 9 AP OD 1
1 8 AP AP 1
1 7 AP AP 1
1 6 AP AP 1
1 5 AP AP 1
1 4 AP OD 1
1 3 AP OD 1
1 2 AP OD 1
1 1 AP OD 1

I want the ouput is to select all except the last 2 row... because it's current status...

If you just want to ignore the last 2 rows then: order the rows, then assign a ROWNUM pseudo-column to the ordered rows, then filter on the ROWNUM to exclude the latest two rows:

SELECT *
FROM   (
  SELECT t.*,
         ROWNUM AS rn
  FROM   (
    SELECT *
    FROM   table_name
    ORDER BY track DESC
  ) t
)
WHERE  rn >= 3;

Or, using the ROW_NUMBER analytic function:

SELECT *
FROM   (
  SELECT t.*,
         ROW_NUMMBER() OVER (ORDER BY track DESC) AS rn
  FROM   table_name t
)
WHERE  rn >= 3;

Or, from Oracle 12:

SELECT *
FROM   table_name
ORDER BY track DESC
OFFSET 2 ROWS
FETCH FIRST 100 PERCENT ONLY;

db<>fiddle here

  • Related