Need help on this trigger which updating a record when user perform update on particular column.
Ex. here I have created a table orders as below.
CREATE TABLE orders
( order_id number(5),
quantity number(4),
status_c varchar2(15),
delete_date date,
deleted_by_id varchar2(10));
I have inserted 2 records in it as below.
insert into orders values (1,25,'FAILED',null,null);
insert into orders values (1,50,'QUEUED',null,null);
select * from orders;
ORDER_ID QUANTITY STATUS_C DELETE_DA DELETED_BY
1 25 FAILED
1 50 QUEUED
Now we can see the values for column STATUS_C as 'FAILED' and 'QUEUED'
So I whenever new user updates this table - orders , and make the status as 'DELETED' for status_c, then I need to capture his details such person_id and sysdate, So I have written a below trigger on that table - Orders
CREATE OR REPLACE TRIGGER orders_before_update
BEFORE UPDATE
ON orders
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
If UPDATING then
if upper(:new.status_c) = 'DELETED' then
-- Find username of person performing UPDATE on the table
SELECT user INTO v_username
FROM dual;
-- Update delete_date field to current system date
:new.delete_date := sysdate;
-- Update deleted_by_id field to the username of the person performing the UPDATE
:new.deleted_by_id := v_username
end if;
end if;
END;
/
Warning: Trigger created with compilation errors.
I got error while compile.
I tried to udpate the table to see its impact,
update orders set status_c = 'DELETED' where order_id = 1;
update orders set status_c = 'DELETED' where order_id = 1
*
ERROR at line 1:
ORA-04098: trigger 'DISDBA.ORDERS_BEFORE_UPDATE' is invalid and failed re-validation
I need help what is the issue in trigger, and why it is not compiling.
When I checked the error using below query. it says.
`select * from user_errors where type = 'TRIGGER' and name` ='ORDERS_BEFORE_UPDATE';
NAME TYPE SEQUENCE LINE POSITION
------------------------------ ------------ ---------- ---------- ----------
TEXT
----------------------------------------------------------------------------------------------------
ORDERS_BEFORE_UPDATE TRIGGER 1 20 5
PLS-00103: Encountered the symbol "END" when expecting one of the following:
. ( * # % & = - + ; < / > at in mod not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like
between is null is not || is dangling
The symbol ";" was substituted for "END" to continue.
Need help on this.
Missing semi-colon on this line:
:new.deleted_by_id := v_username
Related
I need to write PL/SQL procedure with cursor for loop to insert/update the data rowwise.
Data from staging table needs to be populated to main table.
It will first check if the project_id and department exist or not in main table,then it will insert/update accordingly.
(Merge cannot be used as per requirement)
So i have staging table which gets populated.
STAGE_PROJECT
So, if the project_id,department exist,contract and scope columns would get updated.
Else the row would get inserted.
Destination table:
PROJECT_DATA
Example: for ERP and SAP, contract and scope would get updated and for DWH,since the project_id and department do not exists, row will get inserted .
Hopes this helps
I created your tables.
CREATE TABLE STAGE_PROJECT
(
PROJECT_ID NUMBER,
DEPARTMENT VARCHAR2(30),
CONTRACT VARCHAR2(30),
"SCOPE" VARCHAR2(30),
FINAL_DATE DATE
);
CREATE TABLE PROJECT_DATA
(
PROJECT_ID NUMBER,
DEPARTMENT VARCHAR2(30),
CONTRACT VARCHAR2(30),
"SCOPE" VARCHAR2(30),
FINAL_DATE DATE
);
And inserted your data.
INSERT INTO PROJECT_DATA(PROJECT_ID, DEPARTMENT) VALUES (1 , 'ERP');
INSERT INTO PROJECT_DATA(PROJECT_ID, DEPARTMENT) VALUES (2 , 'SAP');
INSERT INTO STAGE_PROJECT(PROJECT_ID, DEPARTMENT, CONTRACT, SCOPE) VALUES (1 , 'ERP', 'NEW','FINAL');
INSERT INTO STAGE_PROJECT(PROJECT_ID, DEPARTMENT, CONTRACT, SCOPE) VALUES (2 , 'SAP', 'OLD','UPCOMING');
INSERT INTO STAGE_PROJECT(PROJECT_ID, DEPARTMENT, CONTRACT, SCOPE) VALUES (3 , 'DWH', 'NEW CONTRA','TARGET');
SELECT * FROM PROJECT_DATA;
SELECT * FROM STAGE_PROJECT;
This PLSQL code loop through your STAGE_PROJECT rows
If rows found in the PROJECT_DATA it will update those rows
otherwise, it will insert the row which is not found.
DECLARE
CURSOR SPCUR IS SELECT * FROM STAGE_PROJECT;
EX PLS_INTEGER;
BEGIN
FOR STAGE_PROJECT_REC IN SPCUR
LOOP
SELECT COUNT(*) INTO EX FROM PROJECT_DATA WHERE
PROJECT_ID = STAGE_PROJECT_REC.PROJECT_ID AND
DEPARTMENT = STAGE_PROJECT_REC.DEPARTMENT;
IF EX > 0 THEN
UPDATE PROJECT_DATA SET CONTRACT = STAGE_PROJECT_REC.CONTRACT,
SCOPE = STAGE_PROJECT_REC.SCOPE,
FINAL_DATE = STAGE_PROJECT_REC.FINAL_DATE
WHERE PROJECT_ID = STAGE_PROJECT_REC.PROJECT_ID AND
DEPARTMENT = STAGE_PROJECT_REC.DEPARTMENT;
ELSE
INSERT INTO PROJECT_DATA(PROJECT_ID, DEPARTMENT, CONTRACT, SCOPE, FINAL_DATE)
VALUES (STAGE_PROJECT_REC.PROJECT_ID, STAGE_PROJECT_REC.DEPARTMENT, STAGE_PROJECT_REC.CONTRACT, STAGE_PROJECT_REC.SCOPE, STAGE_PROJECT_REC.FINAL_DATE);
END IF;
END LOOP;
COMMIT;
END;
so i'm trying to create a trigger, but always have an error that says
Trigger LOG_SALARY compiled
LINE/COL ERROR
--------- ------------------------------------------------------------- 2/2 PL/SQL: SQL Statement ignored 3/9 PL/SQL: ORA-00934: group
function is not allowed here Errors: check compiler log
Error(2,2):PL/SQL: SQL Statement ignored
Error(3,9):PL/SQL:ORA-00934:group function is not allowed here
this is my code
'''alter table department add AVG_SALARY number(10);
alter table department add MAX_SALARY number(10);
alter table department add MIN_SALARY number(10);
insert into department (AVG_SALARY, MAX_SALARY, MIN_SALARY) values (AVG(salary), MAX(salary) ,MIN(salary));
create or replace TRIGGER log_salary
after update of salary on employee
for each row
begin
insert into DEPARTMENT(AVG_SALARY, MAX_SALARY, MIN_SALARY)
values(AVG(SALARY),MAX(SALARY),MIN(SALARY));
end;
update department
set salary = salary + 100.0
where SSN =888665555;
select * from DEPARTMENT;'''
could you tell me what is wrong with my code?
thankyou in advance!
You are inserting new rows into the department table. I think you want to update them. The logic looks like this:
create or replace TRIGGER log_salary
after update of salary on employee
for each row
begin
update department
set (AVG_SALARY, MAX_SALARY, MIN_SALARY) =
(select AVG(SALARY), MAX(SALARY), MIN(SALARY)
from employee
where e.department_id = :new.department_id
end;
This however will probably generate a mutating table error. Addressing that is really difficult. For instance, consider this:
emp_id dept_id salary
1 1 10
2 1 10
3 1 5
If you change emp_id's salary to 20, then the max is 20. But if you change the salary to 5, then the max remains 10.
I would suggest that you just use a view to calculate the values on-the-fly.
I have form in which user add information of new born baby with his/her head family name. When add information into table then getting following errors
ORA-00001: unique constraint (PK) violated
ORA-06512: at trigger_name, line 21
ORA-04088: error during execution of trigger
Trigger:
CREATE OR REPLACE TRIGGER "DB_NAME"."TRG_NBB"
AFTER INSERT ON baby
FOR EACH ROW
WHEN (new.status = 'A') DECLARE
v_1 tab_1.col_1%type;
v_2 tab_2.col_2%type;
v_3 tab_2.col_3%type;
v_4 tab_2.col_4%type;
v_5 tab_2.col_5%type;
v_6 date;
newmofid number;
BEGIN
select max(nvl(col_2,0))+1 into newmofid from tab_2;
SELECT distinct col_1,col_2,to_char(col,'DD-MM-YYYY') INTO v_1,v_2,v_6
from table
where tcid = :new.tcid;
SELECT col_4,col_5,col_3 into v_4,v_5,v_3
from tab_2
where col_1 = v_1
and col_2 = v_2;
INSERT INTO tab_2 (all_columns)
VALUES(variable_names);
DBMS_OUTPUT.PUT_LINE('New Born Baby successfully added to member table');
END trg_nbb;
/
ALTER TRIGGER "DB_NAME"."TRG_NBB" ENABLE;
When I execute this sql query It's take 4 to 5 seconds and increment in values very quickly
select max(nvl(col_2,0))+1 into newmofid from tab_2;
Result:
6030819791
Again execute takes 3 to 4 seconds
Result:
6030819798
How to solve this problem?
Thanks
I suspect it is MAX + 1 that causes problems:
select max(nvl(col_2,0))+1 into newmofid from tab_2;
Such a principle is in most cases wrong and will fails, especially in a multi-user environment where two (or more) users at the same time fetch the same MAX + 1 value, do some processing, and - at the time of insert - one of them succeeds (because it is the first), but the rest of them fail because such a value already exists in the table.
I suggest you switch to a sequence, e.g.
create sequence seq_baby;
and then, in your form, do
select seq_baby.nextval into newmofid from dual;
Utilize the Outdoor Clubs & Product database to create a trigger “product_reorder_au” that is associated with an update operation on the product table. The trigger checks to see whether during the update of the quantity_in_stock attribute, if its value gets lower than the reorder_point attribute value for a product. When this situation occurs, the trigger automatically inserts a new purchase order in the purchase_order table. The new purchase order will use the existing supplier_no attribute value for the product in the product table, and the quantity attribute value will be same as the reorder_qty value for the product in the product table. Save the trigger source as a script file.
This is what the product table looks like
So far this is what I have but I am just generally confused on how to update the table and add in what I am guessing would be an if then statement to only update when the reorderpoint is lower than the quantitiy_in_stock.
CREATE TRIGGER product_reorder_au
AFTER UPDATE OF product
for each row
begin
IF Quantity_In_Stock < Reorder_Point
THEN
INSERT INTO Purchase_Order (Po_No, Po_Date, Product_Id, Quantity, Supplier_id)
VALUES ( );
END IF;
END;
--Test Script
update product
set quantity_in_stock = 5
where product_id = 10012;
Attached in the other tables
You need a BEFORE trigger not AFTER trigger. See below:
--Table Preparation
CREATE TABLE product_1 (
quantity_in_stock NUMBER,
reorder_point NUMBER,
product_id NUMBER,
supplier_id NUMBER,
reorder_qty NUMBER
);
INSERT INTO product_1 VALUES (
20,
5,
10010,
500,
25
)
CREATE TABLE purchase_order (
po_no NUMBER,
po_date DATE,
product_id NUMBER,
quantity NUMBER,
supplier_id NUMBER
);
SQL> Select * from product_1;
QYT_IN_STOCK REORDER_PNT PRDT_ID SUPP_ID RERDR_QTY
----------- ---- ----- ----- -----
4 5 10010 500 25
--Trigger
CREATE TRIGGER product_reorder_au BEFORE
UPDATE ON product_1
FOR EACH ROW
WHEN ( new.quantity_in_stock < old.reorder_point )
BEGIN
INSERT INTO purchase_order (
po_no,
po_date,
product_id,
quantity,
supplier_id
) VALUES (
1, --Populate this coulmn by a sequence or by some logic
SYSDATE,
:old.product_id,
:old.reorder_qty,
:old.supplier_id
);
END;
Execution:
SQL> UPDATE product_1
SET
quantity_in_stock = 4
WHERE product_id = 10010;
SQL> SELECT * FROM purchase_order;
PO_NO PO_DATE PRODUCT_ID QTY SUPP_ID
----- ------- -------- ---- -------
1 25-10-18 10010 25 500
I'm getting a curious error on a BEFORE INSERT TRIGGER, which I can't understand. Even after reading multiple questions posted here with similar problems.
failed to process "method": category_id = 'foo' and request_id = '99'
error: java.sql.BatchUpdateException: ORA-04091: table SCHEMA.ANIMAL_TABLE
is mutating, trigger/function may not see it ORA-06512: at
"SCHEMA.TRIGGER_NAME", line 7 ORA-04088: error during execution of
trigger 'SCHEMA.TRIGGER_NAME'
Here is the trigger:
CREATE OR REPLACE TRIGGER TRIGGER_NAME
BEFORE INSERT ON animal_table FOR EACH ROW WHEN (NEW.animal_type = 'cats')
DECLARE base_animal_id NUMBER(19,0); base_amount NUMBER(19,0);
BEGIN
SELECT animal_nbr INTO base_animal_id
FROM animal_table
WHERE category_id = :NEW.category_id AND summary_id = :NEW.summary_id
AND animal_type = 'special';
SELECT animal_amount INTO base_amount
FROM animal_table
WHERE category_id = :NEW.category_id AND summary_id = :NEW.summary_id
AND animal_type = 'special';
IF :NEW.category_id = 'foo' THEN
:NEW.animal_info1 := base_animal_id;
:NEW.animal_info2 := base_amount;
:NEW.animal_info3 := '00';
END IF;
END;
I know the rules regarding modifications on the same table which the trigger is being held, but I also red something that it should work when changing new columns and only for the :NEW fields. I also thought it may be missing the UPDATE as trigger event, but that was not the case. Can anyone help me please? As I am new to triggers and PL/SQL.
The error message has nothing to do with updating the table. You cannot SELECT from the table that is currently being changed in a ROW level trigger.
The only workaround for this is to write the new rows into a intermediate table in the row level trigger. Then create a statement level trigger that processes all rows that have been written into the intermediate table (most probably only a single UPDATE statement with a subselect).
You might get away without the row level trigger and the intermediate table if you can identify the rows to be post-processed inside the statement level trigger e.g. by checking animal_type = 'cats' and category_id = 'foo'.
If that is the case, the following trigger (untested!!!) might do what you want (instead of the one you have)
CREATE OR REPLACE TRIGGER TRIGGER_NAME
AFTER INSERT ON animal_table
BEGIN
UPDATE animal_table
SET (animal_info1,
animal_info2,
animal_info3) = (SELECT animal_nbr, animal_amount, '00'
FROM animal_table t2
WHERE t2.category_id = animal_table.category_id
AND t2.sumary_id = animal_table.summary_id
AND t2.animal_type = 'special'
)
WHERE animal_type = 'cats'
AND category_id = 'foo'
END;
Another more general PL/SQL thing: You don't need to run one SELECT for each column you want to retrieve, you can do that in a single select statement if the conditions are the same:
SELECT animal_nbr, animal_amount
INTO base_animal_id, base_amount
FROM animal_table
WHERE category_id = :NEW.category_id
AND summary_id = :NEW.summary_id
AND animal_type = 'special';
(Note the two columns in the select and into list)