简体   繁体   中英

Create trigger to keep the latest record

I have a Product table which keeps on adding rows with product_id and price . It has millions of rows.

It has a product_id as Primary key like below.

CREATE TABLE ProductPrice(
product_id VARCHAR2(10),
prod_date DATE ,
price NUMBER(8,0) ,
PRIMARY KEY (product_id)
)

Now this has millions of rows and to get the latest price it get a lot of time.

So to manage the latest price, I have created another table which will keep only the latest price with same format.

CREATE TABLE ProductPriceLatest(
product_id VARCHAR2(10),
prod_date DATE ,
price NUMBER(8,0) ,
PRIMARY KEY (product_id)
)

And on every insert on original table, i will write a trigger which will update the row in this table.

But how can i get the newly inserted values inside the trigger body?

I have tried something like this:

CREATE OR REPLACE TRIGGER TRIG_HISTory
AFTER INSERT
  on ProductPriceLatest
  FOR EACH ROW 

DECLARE

BEGIN

UPDATE latest_price
SET price = NEW.price , 
WHERE product_id = NEW.product_id ;        

END;

Thanks in advance.

You need to use the :new keyword to differentiate with :old values. Also, better use AFTER trigger:

CREATE OR REPLACE TRIGGER TRIG_HISTORY 
AFTER INSERT ON source_table_name
    FOR EACH ROW
DECLARE

BEGIN
MERGE INTO dest_table_name d
    USING (select :new.price p, :new.product_id p_id from dual) s
    ON (d.product_id = s.p_id)
  WHEN MATCHED THEN
    UPDATE SET d.price = s.p
  WHEN NOT MATCHED THEN
    INSERT (price, product_id)
    VALUES (s.p, s.p_id);
END;

Retrieving the latest price from your first table should be fast if you have the correct index. Building the correct index on your ProductPrice table is a far better solution to your problem than trying to maintain a separate table.

Your query to get the latest prices would look like this.

SELECT p.product_id, p.prod_date, p.price
  FROM ProductPrice p
  JOIN (
           SELECT product_id, MAX(prod_date) latest_prod_date
             FROM ProductPrice
            GROUP BY product_id 
       ) m  ON p.product_id = m.product_id 
           AND p.prod_date = m.latest_prod_date
 WHERE p.product_id = ????

This works because the subquery looks up the latest product date for each product. It then uses that information to find the right row in the table to show you.

If you create a compound index on (product_id, prod_date, price) this query will run almost miraculously fast. That's because the query planner can find the correct index item in O(log n) time or better.

You can make it into a view like this:

CREATE OR REPLACE VIEW ProductPriceLatest AS
SELECT p.product_id, p.prod_date, p.price
  FROM ProductPrice p
  JOIN (
           SELECT product_id, MAX(prod_date) latest_prod_date
             FROM ProductPrice
            GROUP BY product_id 
       ) m  ON p.product_id = m.product_id 
           AND p.prod_date = m.latest_prod_date;

Then you can use the view like this:

SELECT * FROM ProductPriceLatest WHERE product_id = ???

and get the same high performance.

This is easier, less error-prone, and just as fast as creating a separate table and maintaining it. By the way, DBMS jargon for the table you propose to create is materialized view.

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