PL/SQL Triggers to update selected rows in column in another table - plsql

I'm trying to create a trigger for my 'rentals' table that will change the value in a certain column ('rent_avail') from another table when an update occurs in the former table. The idea is simple: when a dvd is returned to the dvd store (i.e. date_return has a date value, the dvd has now become available again for renting. Thus, my 'rent_avail' column for the record (dvd) in question should reflect this by being set to 'Y' (the alternative is 'null' when the dvd is currently being rented out). My trigger is being created without errors, but after an insert on the date_return column, all values in my DVD table are being changed. I want to know how can I simply modify the column values in 'rent_avail' column in my dvd table for only the row being updated! This is probably very trivial, but I have researched it and can't seem to find a solution easily..
CREATE OR REPLACE TRIGGER RENTAL_RETURNS
AFTER UPDATE OF DATE_RETURN ON RENTAL
FOR EACH ROW
BEGIN
IF :OLD.DATE.RETURN IS NULL AND :NEW.DATE_RETURN IS NOT NULL THEN
UPDATE DVD SET RENT_AVAIL = 'Y' WHERE DVD.DVD_ID = DVD_ID;
END IF;
END;
/

your update statement is not picking dvd_id from parent table rebtal, but evaluating like where dvd_id = dvd_id which will always be TRUE. Just ad :OLD qualifier and you should be good, considering this is same column name (dvd_id) in rental table.
CREATE OR REPLACE TRIGGER RENTAL_RETURNS
AFTER UPDATE OF DATE_RETURN ON RENTAL
FOR EACH ROW
BEGIN
IF :OLD.DATE.RETURN IS NULL AND :NEW.DATE_RETURN IS NOT NULL THEN
UPDATE DVD SET RENT_AVAIL = 'Y' WHERE DVD.DVD_ID = :OLD.DVD_ID;
END IF;
END;

It looks to me like there's a period where there should be an underscore in the IF statement - I think it should read
IF :OLD.DATE_RETURN IS NULL AND :NEW.DATE_RETURN IS NOT NULL THEN`
Share and enjoy.

Related

Need to delete/insert that corresponding row in that table, as there is duplicate data coming up- PLSQL

I need a help in getting the PLSQL procedure to : Insert/Delete the rows of a table , because as I used Update functionality getting duplicates for that particular Sequence ID field.
So for a particular sequence ID row, whenever I insert the data, it should be the latest in that table.
The last sentence you wrote suggests that you have to
delete row(s) whose ID equals that particular "sequence ID" value
then insert a new row
If you expected some code to be written, you should have posted some more info (CREATE TABLE and INSERT INTO sample data, as well as the way you manipulate it by inserting new row, showing what you expect to happen with old one(s)). It is difficult to write code based on unknown data model.
A guess...
INSERT INTO schema_name.table_name(
primary_key_column
, other_column
)
VALUES(
(SELECT max(primary_key_column)+1 FROM schema_name.table_name),
, 'other_value'
);
COMMIT;
This is the procedure I am using:
https://drive.google.com/file/d/1eGbxSppjexpICKh6pzuW0ZzckVxA6BB0/view?usp=sharing
My requirement when we need to insert the new data , the previous data should be deleted for the corresponding ID.
In the above procedure I am updating the data.

How do I make a trigger with an increment for the values in a column?

I have two tables TRIP and DRIVER. When a new set of values in inserted into TRIP (to indicate a new trip being made), the values in the column TOTALTRIPMADE (which is currently empty) in the table DRIVER will increase by one. The trigger should recognise which row to update with the select statement I've made.
This is the trigger I've made:
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE := OLD.TOTALTRIPMADE+1
WHERE (SELECT L#
FROM TRIP
INNER JOIN DRIVER
ON TRIP.L# = DRIVER.L#;)
END;
/
However I get this error:
ORA-04098: trigger 'CSCI235.UPDATETOTALTRIPMADE' is invalid and failed re-validation
What should I edit in my code so that my trigger works? Thanks!
One error you made is in trying to reference OLD.TOTALTRIPMADE in your SET clause since no alias OLD exists, and unless the table TRIP contains a TOTALTRIPMADE column then the :OLD record won't contain a TOTALTRIPMADE column either (note that since this is an insert trigger the :OLD record either won't exist or won't contain any meaningful data anyway). Another error is in your WHERE clause where you are selecting L# from TRIP joined to DRIVER, but you aren't linking it back to the DRIVER table that you are attempting to update. Instead just update DRIVER where L# is equal the :NEW value of L# from the trip table. The final error I noticed is your use of , the := assignment operator which is for PLSQL code, however you are using it within SQL so just use = without the colon:
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE = nvl(TOTALTRIPMADE,0)+1
WHERE L# = :NEW.L#;
END;
/
Your code has syntax error due to which the trigger is not compiling,I have modified the trigger and it should get compiled successfully with desired results.Please check and feedback.
Please find below the script to create table and compile the trigger,
drop table trip;
create table trip (trip_id number(10),L# varchar2(10));
drop table driver;
create table driver(driver_id number(10),TOTALTRIPMADE number(10),L# varchar2(10));
drop trigger updatetotaltripmade;
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
DECLARE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE = nvl(TOTALTRIPMADE,0) + 1
WHERE DRIVER.L# = :new.L#;
END;
/
select * from ALL_OBJECTS where object_type ='TRIGGER';
Output is below from the tests i did on https://livesql.oracle.com/apex/
There are no issues in the code.The trigger is compiled successfully and is valid.

SQLite trigger Issue

I have a trigger on a table which gets triggered on any new insert...Here is the code for the trigger. This trigger has to calculate duration in seconds and insert the record in the table.
CREATE TRIGGER duration_trigger
BEFORE INSERT on StudentData
BEGIN
UPDATE StudentData set duration = (select cast( (julianday(enddatetime) - julianday(startdatetime) ) *24 * 60 *60 as integer) from StudentData);
END
In StudentsData table Duration column is defined as INTEGER,
StartDatetime and EndDatetime are defined as TEXT
Here comes my issue.
Trigger gets triggered, but the value in Duration column is always 7
When I execute the same select query that is in the the trigger in a SQL tool, it gives me correct duration in seconds. Trigger on the database is not producing the same result...what could be the issue?
I am also attaching screenshots of the trigger data in the table and select query results from same table.
Table results after trigger.
Select Query results
Basically you are updating all rows as you are not specifying a WHERE clause for the update. So the very last successful update will apply the value to all rows, hence why they are all 7.
Furthermore before you have inserted a row what is there to update? I don't think this can be done an analogy would be; Before you build the wall paint the wall.
Now you could UPDATE after the insert, but care needs to be taken when using UPDATE i.e. if you want to update anything other than all rows then you need to restrict the update to the required rows. A WHERE clause can do this.
As such if you were to ensure that an inserted column were set to an invalid value (as far as your view of the data e.g. a duration of -1 would only suit Dr. Who (apologies to any other Time Travellers)).
Null could also be used.
However, I prefer using a value that is specifically set. Assuming that the row is inserted with duration being given a value of -1 (e.g. duartion INTEGER DEFAULT -1) Then :-
CREATE TRIGGER duration_trigger001
AFTER INSERT on StudentData
BEGIN
UPDATE StudentData SET duration = ((julianday(enddatetime) - julianday(startdatetime)) * 24 * 60 * 60) WHERE duration = -1;
END;
Would work e.g. :-
Notes
The first two rows were added before the trigger was created.
Row 10 was deleted because I used . instead of : as a separator it did nothing.
I didn't cast to INT for simplicity/laziness.

ORA-04091: table name is mutating

I get ORA-04091 Error while inserting data into table A. Table A records are refferencing other records in the same table 1:N.
Father records have fk_id = null and child records have fk not null.
create or replace trigger TRBI_A
BEFORE INSERT ON A
for each row
BEGIN
IF :new.fk_id IS NOT NULL then
UPDATE A SET actualTS = CURRENT_TIMESTAMP WHERE id = :new.fk_id;
END IF;
END;
ORA-04091: table name is mutating, trigger/function may not see it
The problem could is probably caused by trigger which tried to modify or query a table that is currently being modified by the statement that fired the trigger.
Does anyone know how to modify the trigger to have it correct?
You know what the problem is, so just read your code a little: you update the same table you are putting the trigger on.
I guess in your case you just need to put :NEW.actualTS:=current_timestamp, without using the update statement.

Select for Update sql is a read and write mode?

I have simultaneous request to a particular row in a table and PL/SQL statement is used to update the table by reading the data from master row in the same table and update the current range row and master row it read.
Algorithm is like this:-
Declare
variable declaration
BEGIN
Select (Values) into (values1) from table where <condition1> for update;
select count(*) into tempval from table where <condition2>;
if (tempval == 0) then
insert into table values(values);
else
select (values) into (values2) from table where <condition2> for update;
update table set (values1) where <condition2>;
end if
update table set (values1+incrval) where <condition1>
END;
Unfortunately the master row is updated properly with the correct sequence but the current range picks up the old value of the master range. It does the dirty read. Even though the transaction isolation level for the table is serialized.
Please could some tell me what is happening here?
This is working as designed. Oracle default, and only, read isolation lets the session see all of their own updates. If you perform:
INSERT INTO TABLE1 (col1) values (1);
COMMIT;
UPDATE TABLE1 SET col1 = 2 where col1 = 1;
SELECT col1 FROM TABLE1;
you will see 2 returned from the last query. Please read the Merge Explanation for how to use a MERGE statement to perform the insert or update based upon a single criteria.

Resources