mavera
mavera

Reputation: 3241

A query which shows changes of a column from a table

i have table which include my product table's logs like that:

process_time             product_id  product_type_id
04.07.2009 14:08:43      5           4
05.07.2009 15:08:43      5           4
06.07.2009 16:08:43      5           6
07.07.2009 16:08:43      5           6
08.07.2009 17:08:43      5           4
08.07.2009 18:08:43      5           4

I want to write a query which shows the changes of product_type_id. For the example above, the result of my query should be like that:

process_time             product_id  product_type_id
04.07.2009 14:08:43      5           4
06.07.2009 16:08:43      5           6
08.07.2009 17:08:43      5           4

How can I write this query?

Upvotes: 4

Views: 167

Answers (2)

hol
hol

Reputation: 8423

Like this:

select * from
(select process_time, product_id, product_type_id
,lag(product_type_id) over (partition by product_id order by process_time) as prevrow
,lead(product_type_id) over (partition by product_id order by process_time) as nextrow
from products )
where nextrow <> product_type_id or nextrow is null;

For all who like to see how this works:

create table products (process_time  timestamp, product_id number, product_type_id number);

insert into products values (to_date('2009-07-04 14:08:43','YYYY-MM-DD hh24:mi:ss'),5,4);
insert into products values (to_date('2009-07-05 15:08:43','YYYY-MM-DD hh24:mi:ss'),5,4);
insert into products values (to_date('2009-07-06 16:08:43','YYYY-MM-DD hh24:mi:ss'),5,6);
insert into products values (to_date('2009-07-07 16:08:43','YYYY-MM-DD hh24:mi:ss'),5,6);
insert into products values (to_date('2009-07-08 17:08:43','YYYY-MM-DD hh24:mi:ss'),5,4);
insert into products values (to_date('2009-07-08 18:08:43','YYYY-MM-DD hh24:mi:ss'),5,4);

commit;

select process_time, product_id, product_type_id
,lag(product_type_id) over (partition by product_id order by process_time) as prevrow
,lead(product_type_id) over (partition by product_id order by process_time) as nextrow
from products 
order by process_time;

select * from
(select process_time, product_id, product_type_id
,lag(product_type_id) over (partition by product_id order by process_time) as prevrow
,lead(product_type_id) over (partition by product_id order by process_time) as nextrow
from products )
where nextrow <> product_type_id or nextrow is null;

commit;

drop table products;

Executed we get:

Table created.
1 row created.
1 row created.
1 row created.
1 row created.
1 row created.
1 row created.
Commit complete.

PROCESS_TIME                    PRODUCT_ID PRODUCT_TYPE_ID    PREVROW    NEXTROW
------------------------------- ---------- --------------- ---------- ----------
04-JUL-09 02.08.43.000000 PM             5               4                     4
05-JUL-09 03.08.43.000000 PM             5               4          4          6
06-JUL-09 04.08.43.000000 PM             5               6          4          6
07-JUL-09 04.08.43.000000 PM             5               6          6          4
08-JUL-09 05.08.43.000000 PM             5               4          6          4
08-JUL-09 06.08.43.000000 PM             5               4          4           


6 rows selected.

PROCESS_TIME                    PRODUCT_ID PRODUCT_TYPE_ID    PREVROW    NEXTROW
------------------------------- ---------- --------------- ---------- ----------
05-JUL-09 03.08.43.000000 PM             5               4          4          6
07-JUL-09 04.08.43.000000 PM             5               6          6          4
08-JUL-09 06.08.43.000000 PM             5               4          4           


3 rows selected.
Commit complete.
Table dropped.

Upvotes: 4

Mike Meyers
Mike Meyers

Reputation: 2895

Use the LAG analytic function to find the prior value of the product_type_id column. If the current and prior values are different then that should be the row that you want. For the first row, the LAG function will return null because there is no prior row so you will also need to test for that.

select 
  process_time, 
  product_id, 
  product_type_id, 
from (
  select 
    process_time, 
    product_id, 
    product_type_id, 
    lag(product_type_id) over (order by process_time) as prior_product_type_id
  from the_table
)
where 
  (prior_product_type_id <> product_type_id or prior_product_type_id is null)

Upvotes: 2

Related Questions