I have a table called film:
CREATE TABLE film (
film_id NUMBER(5) NOT NULL,
title varchar2(255),
description varchar2(255),
release_year NUMBER(4) DEFAULT NULL,
language_id NUMBER(3) NOT NULL,
original_language_id NUMBER(3) DEFAULT NULL,
rental_duration NUMBER(3) DEFAULT 3 NOT NULL,
rental_rate NUMBER(4,2) DEFAULT '4.99',
length NUMBER(5) DEFAULT NULL,
replacement_cost NUMBER(5,2) DEFAULT '19.99' NOT NULL,
rating varchar2(8) DEFAULT 'G',
special_features varchar2(255) DEFAULT NULL
);
And I tried to make a trigger that increased rental rates of films depending on the special feature it has (can only have one). And I came up with the following trigger (for oracle and it compiles with no error)
CREATE OR REPLACE TRIGGER INCREASE_RENTAL_RATE
BEFORE INSERT ON FILM
FOR EACH ROW
DECLARE
change number(4,2);
BEGIN
DBMS_OUTPUT.put_line('mytrigger STARTING');
IF (:NEW.SPECIAL_FEATURES = 'Trailers') THEN
change := 0.1;
DBMS_OUTPUT.put_line('Trailer Read');
END IF;
IF (:NEW.SPECIAL_FEATURES = 'Commentaries') THEN
change := 0.5;
DBMS_OUTPUT.put_line('Commentary read');
END IF;
IF (:NEW.SPECIAL_FEATURES = 'Deleted Scenes') THEN
change := 0.2;
DBMS_OUTPUT.put_line('DS read');
END IF;
IF (:NEW.SPECIAL_FEATURES = 'Behind the Scenes') THEN
change := 0.2;
DBMS_OUTPUT.put_line('BS read');
END IF;
DBMS_OUTPUT.put_line('new=' || :NEW.rental_rate);
UPDATE FILM
SET FILM.RENTAL_RATE = FILM.RENTAL_RATE + change
WHERE FILM.FILM_ID = :NEW.FILM_ID;
DBMS_OUTPUT.put_line('new=' || :NEW.rental_rate);
DBMS_OUTPUT.put_line('mytrigger FINISHED');
END;
Since it compiles with no errors I don't know where to look for problems, but it's not working, I used a dummy example:
INSERT INTO FILM VALUES(20001, 'SUPREMO BORROWERS', 'An exasdafaf', 1978, 1, NULL, 5, '2.99', 52, '11.99', 'PG-13', 'Trailers');
In it, the rental rate is 2.99 and it continues to be 2.99 when I select the film with film_id = 20001...
Here is the output received:
"mytrigger STARTING
Trailer Read
new=2.99
new=2.99
mytrigger FINISHED
1 row(s) inserted."
Which means it knows it had a trailer but the update isn't working
Can anybody help me understand why?
Thanks :)
This is a before trigger, and you are attempting to directly update the row which is about to be inserted / updated in the table (which might not exist yet, and if it did, would likely be overwritten again by the actual update). Instead of the table update, simply change the value of the new pseudo row:
:new.RENTAL_RATE := :new.RENTAL_RATE + change;
Edit
As per below comments, the above didn't work for the OP in this case. However, the following did:
SELECT :new.RENTAL_RATE + change INTO :new.RENTAL_RATE FROM DUAL;
Related
How i can put result rows of this cursor, into column ?
CURSOR CUR1 IS SELECT FILMS.FILM_CODE from FILMS where FILMS.ID_FILM = ID_FILM_ FOR UPDATE OF FILM_CODE;
I wanna put this rows into FILM_CODE column of table below
CREATE TABLE SESSIONF(
ID_SESSION INTEGER DEFAULT SESSION_ID_SEQ.NEXTVAL NOT NULL,
FILM_CODE INTEGER NOT NULL,
NAMEOFGENRE VARCHAR2(200) NOT NULL,
HALL_CODE INTEGER NOT NULL,
NUMBEROFFREEPLACES INTEGER NOT NULL,
COST INTEGER NOT NULL,
DATA_OF_SESSION DATE,
CONSTRAINT PK_ID_SESSION PRIMARY KEY (ID_SESSION)
)
TABLESPACE TBS_PERM_KINO;
Sorry if topic with the same issue already exist, couldn't find it.
EDIT
Procedure on update
create or replace procedure UpdateFILM(ID_FILM_ FILMS.ID_FILM%TYPE,FILM_CODE_ IN FILMS.FILM_CODE%TYPE,FILM_ IN FILMS.FILM%TYPE,GENRE_CODE_ FILMS.GENRE_CODE%TYPE,DIR_CODE_ FILMS.DIRECTOR_CODE%TYPE,YEAROFRELEAS_ FILMS.YEAROFRELEAS%TYPE)
is
varible int := 0;
varible2 int := 0;
varible3 int := 0;
varible4 int := 0;
CURSOR CUR1 IS SELECT FILMS.FILM_CODE from FILMS where FILMS.ID_FILM = ID_FILM_ FOR UPDATE OF FILM_CODE;
F_CODE SESSIONF.FILM_CODE%TYPE;
begin
select count(*) INTO VARIBLE from FILMS where FILM_CODE_ = FILMS.FILM_CODE;
select count(*) INTO VARIBLE2 from DIRECTORS where DIR_CODE_ = DIRECTORS.DIRECTOR_CODE;
IF varible != 0
THEN DBMS_OUTPUT.put_line('FILM_CODE_ erro : there is ALREADY THE SAME FILM_CODE');
ELSIF varible2 =0
THEN DBMS_OUTPUT.put_line('DIR_CODE_ ERR : there IS NO SUCH DIRECTOR_CODE');
ELSIF varible3 !=0
THEN DBMS_OUTPUT.put_line('GENRE_CODE_ ERR : there IS NO SUCH GENRE_CODE_');
ELSIF TO_DATE('12/12/1941', 'DD/MM/YYYY') > YEAROFRELEAS_
THEN DBMS_OUTPUT.put_line('YEAROFRELEAS_ erro : DATE IS LESS THEN 1941');
ELSIF TO_DATE('12/12/3000', 'DD/MM/YYYY') < YEAROFRELEAS_
THEN DBMS_OUTPUT.put_line('YEAROFRELEAS_ erro : DATE IS TO HIGH(MORE THEN 3000)');
ELSE
UPDATE FILMS SET
FILMS.ID_FILM = ID_FILM_,
FILMS.FILM_CODE = FILM_CODE_,
FILMS.FILM = FILM_,
FILMS.GENRE_CODE = GENRE_CODE_,
FILMS.DIRECTOR_CODE = DIR_CODE_,
FILMS.YEAROFRELEAS = YEAROFRELEAS_
WHERE FILMS.ID_FILM = ID_FILM_;
OPEN CUR1;
LOOP
FETCH CUR1 INTO F_CODE;
UPDATE SESSIONF SET SESSIONF.FILM_CODE=FILM_CODE_ WHERE F_CODE = SESSIONF.FILM_CODE;
DBMS_OUTPUT.put_line(F_CODE);
EXIT WHEN CUR1%NOTFOUND;
END LOOP;
CLOSE CUR1;
DBMS_OUTPUT.put_line('films update successful');
END IF;
exception
when others
then DBMS_OUTPUT.put_line(sqlerrm);
end;
CREATE sequence FILM_ID_SEQ;
CREATE TABLE FILMS (
ID_FILM INTEGER DEFAULT FILM_ID_SEQ.NEXTVAL NOT NULL,
FILM_CODE INTEGER NOT NULL,
FILM VARCHAR2(200) NOT NULL UNIQUE,
GENRE_CODE INTEGER NOT NULL,
DIRECTOR_CODE INTEGER NOT NULL,
YEAROFRELEAS DATE,
CONSTRAINT PK_ID_FILM PRIMARY KEY (ID_FILM)
)
TABLESPACE TBS_PERM_KINO;
alter table SESSIONF add constraint FK_FILM_CODE_REF_ID_FILM foreign key (FILM_CODE) references FILMS (ID_FILM) ON DELETE CASCADE;
The way you put it, you can't do that.
Why? Because table contains numerous NOT NULL columns, while cursor selects only one column: FILM_CODE. You could store that value, but what will you put into other mandatory columns?
Therefore, you'll have to either fix cursor's select statement so that it fetches additional columns, or modify table and remove not null constraints (or, possibly, set default values for those columns).
On the other hand, why would you use a cursor? Cursor is usually slow (as you'll probably use it in a loop which works row-by-row). Consider
insert into sessionf (filmcode, nameofgenre, ...)
select f.filmcode, ...
from films f
join ... on ...
i have this table:
CREATE TABLE "ALMAT"."PRODUCT"
( "ID" NUMBER(*,0) NOT NULL ENABLE,
"NAME" VARCHAR2(50 BYTE),
"PRICE" NUMBER(*,0),
"DESCRIPTION" VARCHAR2(180 BYTE),
"CREATE_DATE" DATE,
"UPDATE_DATE" DATE,
CONSTRAINT "PRODUCT_PK" PRIMARY KEY ("ID"))
i want to update data in this table, this is my stored procedure:
CREATE OR REPLACE PROCEDURE UPDATEPRODUCT(prod_id int, prod_name varchar2 default null, prod_price int default null) AS
BEGIN
update product
set
name = prod_name,
price = prod_price,
update_date = sysdate
where id = prod_id;
commit;
END UPDATEPRODUCT;
im using optional parameters, how can i update only 1 column? for example: only "NAME" or "PRICE".
Use COALESCE (or NVL) to keep the current value when a NULL value is passed in (or the default is used):
CREATE OR REPLACE PROCEDURE UPDATEPRODUCT(
prod_id PRODUCT.ID%TYPE,
prod_name PRODUCT.NAME%TYPE DEFAULT NULL,
prod_price PRODUCT.PRICE%TYPE DEFAULT NULL
)
AS
BEGIN
UPDATE product
SET name = COALESCE(prod_name, name),
price = COALESCE(prod_price, price),
update_date = SYSDATE
WHERE id = prod_id;
END UPDATEPRODUCT;
Also, do not COMMIT in a stored procedure as it prevents you from chaining multiple procedures together in a single transaction and rolling them all back as a block. Instead, COMMIT from the PL/SQL block that calls the procedure.
You can use NVL function here. So your updated procedure would look alike -
CREATE OR REPLACE PROCEDURE UPDATEPRODUCT(prod_id int,
prod_name varchar2 default null,
prod_price int default null) AS
BEGIN
UPDATE product
SET name = NVL(prod_name, name),
price = NVL(prod_price, price),
update_date = sysdate
WHERE id = prod_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END UPDATEPRODUCT;
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 ;
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).
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;