Oracle trigger insert to other table then modify the original table - oracle

I have theses two tables:
TABLE ASSET_ENTRY_NOTE (
ID NUMBER NOT NULL, --PK
ASSETMDL_ID NUMBER NOT NULL, --FK
DEPT_ID NUMBER NOT NULL, --FK
LOCATION NVARCHAR2(100) NOT NULL,
ASSET_ID NUMBER, --FK TO ASSETS
ACCOUNT_ID NUMBER NOT NULL, --FK
TOTAL_DPRC_DURATION FLOAT(126) NOT NULL,
TOTAL_PROD_HRS FLOAT(126),
AMORTIZATION_PRCNTG FLOAT(126),
ACQUIRE_DATE DATE NOT NULL,
DESCRIPTION NVARCHAR2(200) NOT NULL,
APPRFLAG NUMBER DEFAULT 0 NOT NULL,
WRK_HRS FLOAT(126),
)
TABLE ASSETS (
ID NUMBER NOT NULL, --PK
ASSETMDL_ID NUMBER NOT NULL, --FK
DEPT_ID NUMBER NOT NULL,
LOCATION NVARCHAR2(100) NOT NULL, --FK
ACCOUNT_ID NUMBER NOT NULL,
ACQUIRE_DATE DATE NOT NULL,
TOTAL_DPRC_DURATION FLOAT(126),
BALANCE_CLOSING_DATE DATE,
SELL_VAL FLOAT(126),
RPLCMNT_DISCOUNT FLOAT(126),
DESCRIPTION NVARCHAR2(200) NOT NULL,
)
Note that there's a one to one relationship between the two tables (i.e. ASSET_ENTRY_NOTE.ASSET_ID is Unique.
When the ASSETS_ENTRY_NOTE.APPRFLAG is updated to 1 I have this trigger that:
gets a new primary key sequence for the ASSETS table.
insert data from ASSETS_ENTRY_NOTE to ASSETS.
updates the column ASSETS_ENTRY_NOTE.ASSET_ID to the same value as the primary key value on the sequence.
This is the latest try for my trigger:
CREATE OR REPLACE TRIGGER ENTRYNT_ASSET_TRIG
after UPDATE OF APPRFLAG ON ASSET_ENTRY_NOTE
for each row
when (new.apprflag = 1)
declare
v_asset_id number;
BEGIN
SELECT assets_PK_SEQ.NEXTVAL INTO v_asset_id
FROM DUAL d;
insert into assets (ID,
assets.assetmdl_id,
assets.dept_id,
assets.location,
assets.account_id,
assets.acquire_date,
assets.total_dprc_duration,
assets.description
)
values (v_asset_id,
assetmdl_id,
dept_id,
location,
account_id,
acquire_date,
total_dprc_duration,
description
);
update ASSET_ENTRY_NOTE set asset_id = v_asset_id where ;
END;
The thing is, I know that ASSET_ENTRY_NOTE is a mutating table and the last UPDATE statement is not allowed here, But nothing else is working for me.
What I've already tried:
creating a statement-level trigger to update one value only.
using before instead of after but that's incorrect because I need the values just to insert into the ASSETS.
using a cursor to go through each value changed but I had exact fetch error.
creating a procedure that handles inserting and updating.
Any help would be appreciated.

The design seems quite strange to me, but to answer the question about the trigger:
To change the asset_entry_note row in the trigger, you need a before update trigger. In there you can just assign the value to the asset_id column.
Your insert statement is also wrong. You can table-qualify column names in the column list of an insert statement. And the values clause needs to use the values from the inserted row. You are referencing the target table's columns which is not allowed).
You also don't need a select statement to obtain the sequence value.
Putting all that together, your trigger should look something like this:
CREATE OR REPLACE TRIGGER ENTRYNT_ASSET_TRIG
BEFORE UPDATE OF APPRFLAG ON ASSET_ENTRY_NOTE
for each row
when (new.apprflag = 1)
declare
v_asset_id number;
BEGIN
v_asset_id := assets_PK_SEQ.NEXTVAL;
insert into assets
(ID,
assetmdl_id,
dept_id,
location,
account_id,
acquire_date,
total_dprc_duration,
description)
values
(v_asset_id,
new.assetmdl_id, -- reference the inserted row here!
new.dept_id,
new.location,
new.account_id,
new.acquire_date,
new.total_dprc_duration,
new.description);
new.asset_id := v_asset_id;
END;
/

You have to change the design of the application to have only one table with sign to indicate the membership of a particular entity.
Another way is to create 'after statement' trigger to update all affected rows in ASSET_ENTRY_NOTE with proper values. These rows is to be collected in, for example, package collection in row-level trigger.

I fixed it and it worked:
changed to before.
edited the update statement to an assignment of new so that the last line would become :new.asset_id := v_asset_id ;

Related

table NISHAN.TBL_ADMIN is mutating, trigger/function may not see it

I have a trigger named tr_admin_user_role that automatically insert values into tbl_user_role table when we perform a insert in another table called tbl_admin. There is no error at compile time but whenever I insert a value into tbl_admin table it shows me an error and error is like
This is my tbl_admin table
CREATE TABLE tbl_admin(
admin_id INTEGER,
username VARCHAR2(50) NOT NULL UNIQUE,
passwords VARCHAR2(50) NOT NULL,
email VARCHAR2(100) UNIQUE,
enabled CHAR(1) DEFAULT 1 NOT NULL,
created_at DATE DEFAULT SYSDATE NOT NULL,
CONSTRAINT pk_admin_id PRIMARY KEY(admin_id)
);
tbl_user_role table
CREATE TABLE tbl_user_role(
user_role_id INTEGER,
username VARCHAR2(50) NOT NULL,
user_role VARCHAR2(50) DEFAULT 'ROLE_ADMIN' NOT NULL,
CONSTRAINT pk_user_role_id PRIMARY KEY(user_role_id)
);
Trigger that i have created
CREATE OR REPLACE TRIGGER tr_admin_user_role
AFTER INSERT ON tbl_admin
FOR EACH ROW
DECLARE
new_username TBL_ADMIN.username%TYPE;
BEGIN
SELECT username INTO new_username FROM (
SELECT username FROM tbl_admin ORDER BY username DESC
) WHERE ROWNUM = 1;
INSERT INTO tbl_user_role(username, user_role) VALUES(new_username, 'ROLE_ADMIN');
END;
Insert statement
INSERT INTO tbl_admin(username, passwords) VALUES('nisha', 'nisha');
That's not how you fetch the newly inserted / updated / previous value of a column in a Trigger. You should use the :OLD.column_name and :NEW.column_name to refer the old and new column values.Read the documentation to understand more.
So, your Trigger could be rewritten as
CREATE OR REPLACE TRIGGER tr_admin_user_role AFTER
INSERT ON tbl_admin
FOR EACH ROW
BEGIN
INSERT INTO tbl_user_role (
username,
user_role
) VALUES (
:NEW.username,
'ROLE_ADMIN'
);
END;
/
I assume you are using another trigger to generate
admin_id and user_role_id since they are declared as PRIMARY KEYs
and you are not including them in your inserts.
Db fiddle demo
Here I've used dummy values for those columns.

Cannot insert NULL into, ERROR during execution of trigger

I have created a Trigger on table Customers so that every time a record is deleted from table customers this same record is inserted in table Customer_Archives with the current date as Deletion_Date.
I am have to insert a new customer into table Customers and then delete it. The record must be inserted correctly into table Customers_Archive.
Here's script I have so far:
CREATE TABLE Customer_Archives
(
customer_id NUMBER NOT NULL,
customer_first_name VARCHAR2(50),
customer_last_name VARCHAR2(50) NOT NULL,
customer_address VARCHAR2(255) NOT NULL,
customer_city VARCHAR2(50) NOT NULL,
customer_state CHAR(2) NOT NULL,
customer_zip VARCHAR2(20) NOT NULL,
customer_phone VARCHAR2(30) NOT NULL,
customer_fax VARCHAR2(30),
deletion_date DATE,
CONSTRAINT customer_archives_pk
PRIMARY KEY (customer_id)
);
CREATE OR REPLACE TRIGGER Customers_before_insert
BEFORE DELETE ON Customers
FOR EACH ROW
DECLARE
ar_row Customers%rowtype;
BEGIN
INSERT INTO Customer_Archives
VALUES(ar_row.Customer_id,
ar_row.Customer_First_Name,
ar_row.Customer_Last_Name,
ar_row.Customer_Address,
ar_row.Customer_City,
ar_row.Customer_State,
ar_row.Customer_Zip,
ar_row.Customer_Phone,
ar_row.Customer_Fax,
sysdate());
dbms_output.put_line('New row is added to Customers_Archive
Table with Customer_ID:' ||ar_row.Customer_id ||'on date:' || sysdate());
END;
/
SELECT trigger_name, status FROM user_triggers;
INSERT INTO CUSTOMERS
(customer_id, customer_first_name, customer_last_name, customer_address,
customer_city, customer_state, customer_zip, customer_phone, customer_fax)
VALUES (27,'Sofia','Chen','8888 Cowden St.','Philadelphia','PA',
'19149',7654321234',NULL);
DELETE FROM CUSTOMERS
WHERE customer_id = 27;
When I try to delete the customer that I just inserted I get an error:
Error starting at line : 47 in command -
DELETE FROM CUSTOMERS
WHERE customer_id = 27
Error report -
ORA-01400: cannot insert NULL into ("TUG81959"."CUSTOMER_ARCHIVES"."CUSTOMER_ID")
ORA-06512: at "TUG81959.CUSTOMERS_BEFORE_INSERT", line 4
ORA-04088: error during execution of trigger 'TUG81959.CUSTOMERS_BEFORE_INSERT'
In your DELETE trigger you should be using the :OLD values when creating your archive record:
CREATE OR REPLACE TRIGGER CUSTOMERS_BEFORE_INSERT
BEFORE DELETE ON CUSTOMERS
FOR EACH ROW
BEGIN
INSERT INTO CUSTOMER_ARCHIVES
(CUSTOMER_ID,
CUSTOMER_FIRST_NAME,
CUSTOMER_LAST_NAME,
CUSTOMER_ADDRESS,
CUSTOMER_CITY,
CUSTOMER_STATE,
CUSTOMER_ZIP,
CUSTOMER_PHONE,
CUSTOMER_FAX,
DELETION_DATE)
VALUES
(:OLD.CUSTOMER_ID,
:OLD.CUSTOMER_FIRST_NAME,
:OLD.CUSTOMER_LAST_NAME,
:OLD.CUSTOMER_ADDRESS,
:OLD.CUSTOMER_CITY,
:OLD.CUSTOMER_STATE,
:OLD.CUSTOMER_ZIP,
:OLD.CUSTOMER_PHONE,
:OLD.CUSTOMER_FAX,
SYSDATE());
DBMS_OUTPUT.PUT_LINE('New row is added to Customers_Archive
Table with Customer_ID:' ||:OLD.Customer_id ||'on date:' || SYSDATE());
END;
In your original trigger you'd declared a row variable named ar_row but hadn't assigned anything to any of the fields - therefore they were all NULL. When a BEFORE trigger is invoked during a DELETE, the :OLD values have the values prior to the deletion, and the :NEW values are all NULL.
Best of luck.

Oracle Database Can set Constraint for Upper Case Values?

Is there anyway that we can set a constraint in database table level to have upper or lower case values for certain columns? When we create a table, we can set NOT NULL to avoid having null values on a column. Same way, can we do that for either uppercase or lower case?
You can do that using a check constraint:
create table foo
(
only_lower varchar(20) not null check (lower(only_lower) = only_lower),
only_upper varchar(20) not null check (upper(only_upper) = only_upper)
);
I had almost same case, tried with check constraint, but if the user is not mentioning it as UPPER() or LOWER() it gives error so I took TRIGGER route as below code.
--creating table
create table user_name (
first_name varchar2(50),
last_name varchar2(50));
--creating trigger
CREATE OR REPLACE TRIGGER TRG_USER_NAME_IU
BEFORE INSERT OR UPDATE ON USER_NAME
FOR EACH ROW
BEGIN
:NEW.FIRST_NAME := UPPER(:NEW.FIRST_NAME);
:NEW.LAST_NAME := UPPER(:NEW.LAST_NAME);
END;
/
Can test and share feedback or comments

how to automatic add word in values after insert table in oracle

I have this table:
create table a(
id_a number(5) not null,
name varchar2(15) not null,
address varchar2(30),
phone varchar2(12),
constraint pk_a primary key (id_a)
);
after i insert into table,
i want to add the word automatic behind the values in field "name".
1, Grace, Aussie, 0111111
then, i want to after insert this. the value Grace automatic add S, Comp behind the word.
1, Grace S.Comp, Aussie, 0111111
thanks
You can use a trigger (before insert - for each row):
create trigger your_trigger_name before insert on a for each row
when (new.name is not null)
begin
:new.name := :new.name || ' S.Comp';
end;
This trigger will change "name" column automatically (only when "name" is not null).

Oracle trigger to update an entity in different table

So this is from a uni coursework and is my first time working with Oracle (and using triggers). We are supposed to be creating a database for an airlines.
Part of the database is
CREATE TABLE FLIGHT_BOOKING (
BOOKING_ID NUMBER(11) PRIMARY KEY,
BOOKING_TIME DATE NOT NULL,
EMPLOYEE_ID NUMBER(11) NOT NULL,
FLIGHT_ID NUMBER(11) NOT NULL,
TOTAL_COST NUMBER(4,2) NOT NULL
);
CREATE TABLE FLIGHT (
FLIGHT_ID NUMBER(11) PRIMARY KEY,
PLANE_ID NUMBER(11) NOT NULL,
START_ID NUMBER(11) NOT NULL,
DESTINATION_ID NUMBER(11) NOT NULL,
TRANSIT_ID NUMBER(11),
DEPARTURE_TIME DATE NOT NULL,
ARRIVAL_TIME DATE NOT NULL,
NUM_BOOKED NUMBER (4) NOT NULL
);
CREATE TABLE PASSENGER (
PASSENGER_ID NUMBER(11) PRIMARY KEY,
FIRST_NAME VARCHAR2(20) NOT NULL,
MIDDLE_NAME VARCHAR2(20) NULL,
LAST_NAME VARCHAR2(20) NOT NULL,
TELEPHONE NUMBER(11) NOT NULL,
BOOKING_ID NUMBER(11) NOT NULL
);
So what I want to do is create a trigger such that every time a new passenger is added to the PASSENGER table, the trigger finds the corresponding FLIGHT_ID from the FLIGHT_BOOKING table and increments NUM_BOOKED for the corresponding flight in the FLIGHT table.
I have tried going through the oracle documentation, but i could not find anything that describes a situation where two or more tables are concerned.
Any help would be really appreciated!
you can do it like this:
CREATE OR REPLACE TRIGGER update_flight_booking_info
AFTER INSERT ON PASSENGER
FOR EACH ROW
DECLARE
v_flight_id number;
v_booking_id number;
BEGIN
v_booking_id := :new.booking_id ;
select flight_id into v_flight_id
from flight_booking
where booking_id = v_booking_id;
update flight
set NUM_BOOKED = NUM_BOOKED + 1
where flight_id = v_flight_id;
END;
HTH.
I'd rather not store that number, and calculate it as needed, but okay, it is just course material. :)
When you create a trigger, inside it you can put all kinds of code, including update statements.
So you can write a trigger like this:
create or replace trigger TIDB_BOOKING
before insert or delete
for each row
declare
V_Increment int;
begin
-- Inc or dec, depending on insert or update.
-- Hasn't a booking got a number of seats?
-- Also, can bookings be updated/moved to other flights?
-- These problems aren't yet taken into account in this code.
V_Increment := 1;
if deleting then
V_Increment := -1;
update FLIGHT f
set f.NUM_BOOKED = f.NUM_BOOKED + V_Increment
where f.FLIGHT_ID = nvl(:new.FLIGHT_ID, :old.FLIGHT_ID);
end;

Resources