Creating a trigger that will update an attribute - sql

Question: write a trigger that will update the invoice subtotal each time the line table is updated (a new row inserted, updated or deleted). Include the SQL statements used to test the insert, update and delete.
I'm finding it difficult to properly understand triggers and I don't know why. I understand the basic concept of it (at least I think I do) but I can't seem to understand how to answer my question. The following code is my attempt at answering the above question:
create or replace trigger update_subtotal
after insert or update or delete
on invoice
for each row
begin
insert into line ('inv_number', 'line_number', 'p_code', 'line_units', 'line_price')
values ('1009', '3', '12345-6t', '1', '123.45');
end;
select * from line;
After running this code I ended up with these errors:
Errors: TRIGGER UPDATE_SUBTOTAL
Line/Col: 3/1 PL/SQL: SQL Statement ignored
Line/Col: 3/19 PL/SQL: ORA-00928: missing SELECT keyword
Line/Col: 17/1 PLS-00103: Encountered the symbol "SELECT"
I'm using Oracle Live.
In short: help.

You seem to have the concept backwards. The invoice table needs to be updated when line changes -- so line needs the trigger and the change to invoice is an update. That would be something like this:
create or replace trigger trg_line_update_subtotal
after insert or update or delete
on line
for each row
begin
update invoice i
set total = coalesce(i.total, 0) +
coalesce(:new.line_Units * :new.line_price, 0) -
coalesce(:old.line_Units * :old.line_price, 0)
where i.inv_number = coalesce(:new.inv_number, :old.inv_number);
end;

Related

How to compare two values in different tables with a TRIGGER SQL?

CREATE TRIGGER Comparer_Prix
BEFORE UPDATE ON ARTICLE
FOR EACH ROW BEGIN
SELECT ARTICLE.PRIXVENTE, ARTICLE.N_PRODUIT, ARTICLE.N_FABRICANT, LIEN_FABRICANT_PRODUIT.PRIXFABRICANT, LIEN_FABRICANT_PRODUIT.N_PRODUIT, LIEN_FABRICANT_PRODUIT.N_FABRICANT
FROM ARTICLE, LIEN_FABRICANT_PRODUIT
WHERE ARTICLE.N_FABRICANT=LIEN_FABRICANT_PRODUIT.N_FABRICANT AND ARTICLE.N_PRODUIT=LIEN_FABRICANT_PRODUIT.N_PRODUIT;
IF (NEW.PRIXVENTE< PRIXFABRICANT) THEN RAISE_APPLICATION_ERROR(-20001, 'Refusé');
END IF;
END;
I am trying to create a trigger that codes the following rule: the sales price must always be higher than the manufacturing price.
Here the errors I get:
Error(2,3): PL/SQL: SQL Statement ignored
Error(2,69): PL/SQL: ORA-00904: "LIEN_FABRICANT_PRODUIT"."PRIXFABRICANT" : invalid identifier
Error(2.92): PLS-00302: The component "PRIXFABRICANT" must be declared.
Error(5,3): PL/SQL: Statement ignored
Error(5,10): PLS-00201: the identifier 'NEW.PRIXVENTE' must be declared.
It is not new, but :new (you're missing a colon).
Though, that's not the only issue here; you can't select from a table which is just being modified; mutating table error is expected. Lucky you, you don't have to select from article as you can reference its values using the same :new value.
ORA-00904 means that you've used a column name which doesn't exist in that table. As you didn't post tables' descriptions, I'm simply repeating what you wrote. Fix it yourself.
Something like this:
create or replace trigger comparer_prix
before update on article
for each row
declare
l_prixfabricant lien_fabricant_produit.prixfabricant%type;
begin
select prixfabricant
into l_prixfabricant
from lien_fabricant_produit
where n_fabricatn = :new.n_fabricant
and n_produit = :new.n_produit;
if :new.prixvente < l_prixfabricant then
raise_application_error(-20001, 'Refusé');
end if;
end;
/
Also, it wouldn't harm if you learnt how to properly format code and make it easier to read. Use table aliases (instead of those lengthy table names).
If You compare two tables use:
... WHERE ... AND EXISTS(SELECT * FROM <TAB_COMPARE>)

Oracle PL/SQL - BEFORE INSERT 'table does not exist' error?

I'm taking my first steps in Pl/SQL and am struggling with triggers. I've tried creating the trigger below but am receiving this error:
Error at line 2: PL/SQL: SQL Statement ignored
PL/SQL: ORA-00942: table or view does not exist
To clarify: I have checked the name of the table over and over, and it does exist. It is also in the same schema as the trigger I'm trying to create. The 'customer_seq.NEXTVAL' refers to a sequence created previously that runs without errors.
The code is as follows:
CREATE TRIGGER new_customer
BEFORE INSERT ON customer
FOR EACH ROW
BEGIN
INSERT INTO customer_id VALUES ('c-', customer_seq.NEXTVAL);
END;
Thanks in advance for any help.
You probably intend something like this:
CREATE TRIGGER new_customer
BEFORE INSERT ON customer
FOR EACH ROW
BEGIN
SELECT customer_seq.NEXTVAL INTO :NEW.customer_id
FROM dual;
END;
It is unclear what the purpose of 'C_' is. If it is part of the customer id, I would advise you to stick to numbers.
Also note that more recent versions of Oracle support generated always as identity -- which is much preferred over defining a sequence and trigger.

Audit Table Trigger

Trying to create a trigger for populating an audit table with old data before changes are made to the base table BOOKS
CREATE OR REPLACE TRIGGER populate_audit_table
BEFORE INSERT OR UPDATE OF cost, retail OR DELETE
ON books
REFERENCING NEW as new OLD as old
FOR EACH ROW
DECLARE
dml_operation varchar2(1) :=
CASE WHEN UPDATING THEN 'U'
WHEN DELETING THEN 'D'
ELSE 'I'
END;
BEGIN
INSERT INTO cost_retail_history
(isbn
,title
,pubid
,pubdate
,cost
,retail
,discount
,category
,dml_operation)
SELECT
(old.isbn
,old.title
,old.pubid
,old.pubdate
,old.cost
,old.retail
,old.discount
,old.category
,new.dml_operation)
FROM BOOKS;
end;
I get the following errors:
Errors: TRIGGER POPULATE_AUDIT_TABLE
Line/Col: 8/7 PL/SQL: SQL Statement ignored
Line/Col: 20/13 PL/SQL: ORA-00907: missing right parenthesis
I also tried using VALUES on the INSERT INTO and not designating a source table ("FROM BOOKS")
....VALUES
(old.isbn
,old.title
,old.pubid
,old.pubdate
,old.cost
,old.retail
,old.discount
,old.category
,new.dml_operation);
end;
And I get the following errors:
Line/Col: 8/7 PL/SQL: SQL Statement ignored
Line/Col: 27/18 PL/SQL: ORA-00984: column not allowed here
I've read and re-read https://docs.oracle.com/cd/A64702_01/doc/server.805/a58225/ch4a.htm#1997457 so I feel like I'm missing something simple and just need a point in the right direction.
Thanks,
EDIT:
I dropped the dml_operation as this wasn't required and followed the advice below, but I am still getting errors:
Current version:
CREATE OR REPLACE TRIGGER cost_retail_history
BEFORE INSERT
OR UPDATE OF cost, retail
OR DELETE
ON books
REFERENCING NEW as new OLD as old
FOR EACH ROW
BEGIN
CASE
WHEN INSERTING THEN
INSERT INTO cost_retail_history
(isbn
,title
,pubid
,pubdate
,cost
,retail
,discount
,category)
VALUES
(:new.isbn
,:new.title
,:new.pubid
,:new.pubdate
,:new.cost
,:new.retail
,:new.discount
,:new.category)
WHEN UPDATING cost, retail OR DELETING THEN
INSERT INTO cost_retail_history
(isbn
,title
,pubid
,pubdate
,cost
,retail
,discount
,category)
VALUES
(:old.isbn
,:old.title
,:old.pubid
,:old.pubdate
,:old.cost
,:old.retail
,:old.discount
,:old.category);
END CASE;
END;
I'm getting the errors:
Errors: TRIGGER COST_RETAIL_HISTORY
Line/Col: 4/9 PL/SQL: SQL Statement ignored
Line/Col: 22/5 PL/SQL: ORA-00933: SQL command not properly ended
I can't tell exactly what line the error is on as this would indicate it's with:
...OR DELETE
and
... ,:new.title
which does not make sense to me.
If you were doing insert ... select ... then you should not have the parentheses around the column list; i.e.:
INSERT INTO cost_retail_history
(isbn
...
,dml_operation)
SELECT
old.isbn
...
,new.dml_operation
FROM BOOKS;
but you should not be selecting from the table the trigger is against - partly because you'll get a mutating table error, and you are attempting to insert an audit row for every row in the base table; but mostly because you already have all of the information you need.
With the values clase you need to prefix the old/new values with a colon:
....VALUES
(:old.isbn
,:old.title
,:old.pubid
,:old.pubdate
,:old.cost
,:old.retail
,:old.discount
,:old.category
,:new.dml_operation);
end;
Read more in the documentation.
Oracle has built-in audit tools but presumably this is an exercise.
I can't tell exactly what line the error is on as this would indicate...
This can be slightly confusing with triggers as they are a mix of SQL and PL/SQL. Because you are getting PL/SQL errors the line numbering starts from the beginning of the PL/SQL part, so here BEGIN is line 1, INSERT is line 4; WHEN UPDATING... is line 22.
Those new errors are just because you don't have a semicolon at the end of the first INSERT statement:
,:new.discount
,:new.category);
-----------------------^
WHEN UPDATING cost, retail OR DELETING THEN
INSERT INTO cost_retail_history
The error is reported against line 22 because that WHEN is where it's expecting to see the semicolon, and the first point it can see the previous SQL command hasn't been completed. The error against line 4 is saying where that not-ended command started; so you're getting two messages for one actual problem.

ORA-04071: missing BEFORE, AFTER or INSTEAD OF keyword

I am writing some PL/SQL code for a apex database application. With the code a want to realise that when I make a purchase order, a purchase orderline is automatically generated based on the purchase order_id. However, I'm getting a ORA-04071 error running the code below:
create or replace trigger "INKOOPORDER_T1"/
AFTER insert or update or delete on INKOOPORDER
for each row begin
INSERT INTO INKOOPORDERREGEL
(I_nummer)
SELECT
I_nummer
FROM inkooporderregel
go
end/
Can somebody help me please?
ur query has some syntax errors
try below code
I removed / from first line and after End, put ; at the end of insert statement and deleted go.Also after end a ;
create or replace trigger "INKOOPORDER_T1"
AFTER insert or update or delete on INKOOPORDER
for each row
begin
INSERT INTO INKOOPORDERREGEL
(I_nummer)
SELECT
I_nummer
FROM inkooporderregel;
end;

Creating a INSERT TRIGGER in different table

I need help on creating a trigger on my table1
that will insert specific columns into table2 from table1.
How can i do that? I am using Oracle 11G XE .
Here is my code:
create trigger AllowanceTrigger
on ex_bulacan
after insert
as
insert into allowance VALUES (PLANT_ORIGIN,SO_NO, SO_STATUS,SO_REMARKS,DRIVER_NAME)
select plant_origin, sales_order_no, status,remarks, driver_name
from ex_bulacan;
go ;
When I run that command I get this error
ORA-04071: missing BEFORE, AFTER or INSTEAD OF keyword
The explanation is:
ORA-04071. 00000 - "missing BEFORE, AFTER or INSTEAD OF keyword"
*Cause: The trigger statement is missing the BEFORE/AFTER/INSTEAD OF clause.
*Action: Specify either BEFORE, AFTER or INSTEAD OF.
There is no "go" statement in PL/SQL, and you have not followed the correct syntax for a trigger definition (it is well documented)
Try this:
create trigger AllowanceTrigger
after insert on ex_bulacan
begin
insert into allowance (PLANT_ORIGIN,SO_NO, SO_STATUS,SO_REMARKS,DRIVER_NAME)
select plant_origin, sales_order_no, status,remarks, driver_name
from ex_bulacan;
end;
I'm not sure whether it does what you intended. It fires once per insert statement, not for each row, and it inserts all rows from ex_bulacan into allowance, not just the ones you just inserted. Maybe what you want is actually:
create trigger AllowanceTrigger
after insert on ex_bulacan
for each row
begin
insert into allowance (PLANT_ORIGIN,SO_NO, SO_STATUS,SO_REMARKS,DRIVER_NAME)
values (:new.plant_origin, :new.sales_order_no, :new.status, :new.remarks,
:new.driver_name);
end;
There is a syntax error in your code. You must specify the trigger in this order:
CREATE TRIGGER AllowanceTrigger
AFTER INSERT
ON ex_bulacan