SQL - Trigger "not in" - sql

I'm trying to make a time trigger in the dubbing database. I want to check that character can't be dubbed in the dubbing of the movie in which the character doesn't appear. Here's the PDM:
and CDM
I'm the begginer with SQL but I know that there should be some trigger in the table 'DUBBES'. I tried to make something like this, but i got a message that trigger is invalid:
CREATE OR REPLACE TRIGGER x_character
BEFORE INSERT OR UPDATE ON dubbes FOR EACH ROW
DECLARE
IF ( :NEW.CHAR_id_character NOT IN ( SELECT CHAR_id_CHARACTER
FROM APPEARS
WHERE APPEARS.MOV_id_movie = (SELECT dubbing.Mov_id_movie
FROM DUBBING
WHERE dubbing.id_dubbing = :NEW.dab_id_dubing)))
THEN
RAISE_APPLICATION_ERROR(-20000, 'Character is not in this movie.');
END IF;
END;
/
I would really appreciate any help.
Many thanks in advance!

I think that your code should be like this:
create or replace trigger X_character BEFORE INSERT OR UPDATE ON dubbes
FOR EACH ROW
DECLARE
haveit number;
idmovie number;
begin
select dubbing.Mov_id_movie into idmovie from DUBBING where dubbing.id_dubbing = :new.dab_id_dubing;
select count(*) into haveit from APPEARS
where
APPEARS.MOV_id_movie = idmovie and
APPEARS.CHAR_id_CHARACTER = :new.CHAR_id_character;
IF( haveit = 0 ) then
RAISE_APPLICATION_ERROR(-20000, 'Character is not in this movie.');
END IF;
END;
/

From your diagram, you don't need a trigger for this. If you redefine your FK_DUBBES_DUBBES3_CHARACTE foreign key to refer to APPEARS.CHAR_ID instead of directly against CHARACTER.ID_CHARACTER then the requirement will be enforced for you, without the additional overhead of a trigger.
(As an aside, you might find it easier to have more consistent column names, and simpler key names...)

Begin keyword is missing after DECLARE

Related

How to successfully reference another table before insert with a trigger

I'm trying to create a trigger to validate if a new entry in the table registraties (registrations) contains a valid MNR (employee number) but I'm getting stuck on the part where I'm referencing the table medewerkers (employees).
Could someone help me out?
CREATE OR REPLACE TRIGGER t_MNRcontrole
BEFORE INSERT OR UPDATE
ON registraties
DECLARE
MNR_medewerkers number (SELECT MNR FROM MEDEWERKERS);
FOR EACH ROW
BEGIN
IF :new.MNR <> MNR_medewerkers
THEN raise_application_error(-20111, 'Medewerker niet herkend!');
END IF;
END;
Error message received is
ORA-24344: success with compilation error
The PL/SQL assignment operator is :=, or select x into y from z to populate from a SQL query.
FOR EACH ROW is part of the trigger spec, not the PL/SQL code.
If :new.mnr is not present in the parent table, you will get a no_data_found exception, not a mismatched variable.
It's good practice for error messages to include details of what failed.
In programming, we use indentation to indicate code structure.
A fixed version would be something like:
create or replace trigger trg_mnrcontrole
before insert or update on registraties
for each row
declare
mnr_medewerkers medewerkers.mnr%type;
begin
select mw.mnr into mnr_medewerkers
from medewerkers mw
where mw.mnr = :new.mnr;
exception
when no_data_found then
raise_application_error(-20111, 'Medewerker '||:new.mnr||' niet herkend!');
end;
However, we can implement this kind of check better using a foreign key constraint, for example:
alter table registraties add constraint registraties_mw_fk
foreign key (mnr) references medewerkers.mnr;
MNR_medewerkers number (SELECT MNR FROM MEDEWERKERS);
will always fail because its not a NUMBER, unless your table happens to only have one single entry and even then I am not sure PLSQL will allow it to pass.
The more standard case for this would be to first declare the number, then in the codeblock you do a SELECT INTO along with a WHERE clause where you make sure to only pick one specific row from the table. Then you can compare that number with the new one.
If however you are not trying to compare to one specific row, but are instead checking if the entry exists in that table.
BEGIN
SELECT 1
INTO m_variable
FROM table
WHERE MNR = :new.MNR;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
m_variable = 1;
WHEN OTHERS THEN
m_variable = 0;
END;
Declare the m_variable beforehand, and then check if its 0 then report the error.
The too_many_rows is in case there is more than one row in the table with this MNR, and the OTHERS is there for the NO_DATA_FOUND, but I use OTHERS to handle everything else that could happen but probably wont.
Btw this is a code block to be included within the main code block, so between your BEGIN and IF, then just change the IF to check if the variable is 0.

trigger question in Oracle 18C, 'declare the content'

Hi I do have some problems when I try to create triggers.
`CREATE OR REPLACE TRIGGER summary_check
BEFORE UPDATE OR INSERT ON POST
FOR EACH ROW
BEGIN
IF : NEW.summary != SUBSTR(content,1,11) || '...' THEN
RAISE_APPLICATION_ERROR(-20001,'The summary rule need to be followed');
END IF;
END;`
This one have a compiled problem which I need declare content, then if I use post.content, it tell me that this kind of context is not allowrd? both them are VARVHAR so they are the same type. not user what I should of change here .
`CREATE OR REPLACE TRIGGER date_check
BEFORE UPDATE OR INSERT ON Likes
FOR EACH ROW
DECLARE
V_DATE DATE;
BEGIN
SELECT created_on
INTO V_DATE
FROM post
WHERE post_id = post.post_id;
IF : NEW.liked_on < v_date THEN
RAISE_APPLICATION_ERROR(-20001,'the date have to entered correctly ');
END IF;
END;`
And here is another one, this one has no problem with compile, but when I try to test the trigger, it always say that the exact fetch returns more than requested, not sure how to I change it?
This query:
SELECT created_on
INTO V_DATE
FROM post
WHERE post_id = post.post_id;
Is not doing what you intend. The post_id also refers to post.post_id. So this returns all rows in post where post_id is not NULL.
I think you want:
SELECT p.created_on
INTO V_DATE
FROM post p
WHERE :NEW.post_id = p.post_id;
For your first problem, I think you don't even need trigger if both the columns used in the trigger belongs to the same table.
It can be done via adding CHECK constraint.
Alter table post
Add constraint summary_check
Check (summary = SUBSTR(content,1,11) || '...');
For the second problem, as mentioned by #gordon, just use :new.post_id instead of post.post_id.
Cheers!!

How to user trigger to update a column comparing with system date in Oracle?

I wrote this trigger to update a certain column. The trigger I wrote is this:
CREATE TRIGGER updateotMark
BEFORE UPDATE
ON sBookBorrow
FOR EACH ROW
WHEN(SYSDATE-to_date(etime)>15)
BEGIN
UPDATE otMark = 1;
END;
/
This is the first time I use trigger, so I have no idea what went wrong. Any ideas? Thanks everyone for your answer.
UPDATE: This is what I got in the console. What did I do wrong?
UPDATE2:Now it has a error message:ERROR at line 5:
ORA-04076: invalid NEW or OLD specification
What is the data type of "etime"?
If date, you don't need to use "TO_DATE" function. ex.(SYSDATE - etime > 15)
If VARCHAR2, you need to put the format. ex. TO_DATE(etime,'YYYYMMDD')
However, use SHOW in SQLPlus will give you more information about error.
SHOW ERROR TRIGGER updateotMark;
Let try this.
CREATE OR REPLACE TRIGGER updateotMark
BEFORE UPDATE
ON sBookBorrow
FOR EACH ROW
WHEN (SYSDATE - NEW.etime > 15)
BEGIN
:NEW.otmark := 1;
END;
Just update the :new value
CREATE TRIGGER updateotMark
BEFORE UPDATE
ON sBookBorrow
FOR EACH ROW
WHEN(SYSDATE-to_date(etime)>15)
BEGIN
:new.otmark = 1;
END;

PostgreSQL 1 to many trigger procedure

I wrote this query in PostgreSQL:
CREATE OR REPLACE FUNCTION pippo() RETURNS TRIGGER AS $$
BEGIN
CHECK (NOT EXISTS (SELECT * FROM padre WHERE cod_fis NOT IN (SELECT padre FROM paternita)));
END;
$$ LANGUAGE plpgsql;
It returns:
Syntax error at or near CHECK.
I wrote this code because I have to realize a 1..n link between two tables.
You can't use CHECK here. CHECK is for table and column constraints.
Two further notes:
If this is supposed to be a statement level constraint trigger, I'm guessing you're actually looking for IF ... THEN RAISE EXCEPTION 'message'; END IF;
(If not, you may want to expand and clarify what you're trying to do.)
The function should return NEW, OLD or NULL.

PLS-00103, in Trigger

create or replace TRIGGER log_worlds BEFORE UPDATE OR INSERT ON worlds
DECLARE
ac VARCHAR2(50);
tab VARCHAR2(50);
world VARCHAR2(50);
BEGIN
IF UPDATING THEN
ac:='Aktualizacja';
END IF;
IF INSERTING THEN
ac:='Nowe';
END IF;
tab:='WORLDS';
world:='world_';
world:=world||cast(NEW_WORLD.NEXTVAL as VARCHAR2(10));
INSERT INTO log(ACTION_DATE,ACTION,TAB_NAME,ADDED_WORLD) VALUES(SYSDATE,ac,tab,world);
INSERT INTO worlds(WORLD_NAME) VALUES(world);
END;
Can someone help me with this,error information is about line 14? This trigger is supposed to add new values to the log table and to change the primary key value of the worlds table when my APEX application issues DML against the table.
the error you get suggests some syntax error in your code which I can't immediately find. However I would expect another error becuase Oracle won't allow you do execute DML statements (select, insert, update, delete) inside of a trigger on the same table as the trigger is on. Your trigger is on table worlds, so you are not allowed to insert a record into table worlds inside the trigger.
I think it's this line here:
world:=world||cast(NEW_WORLD.NEXTVAL as VARCHAR2(10));
If you replace it with:
world := world||to_char(NEW_WORLD.NEXTVAL);
it should work.
Btw: directly using a nextval call in an assignment does not work on versions prior to 11.x (not sure about the value of x here).
In 10.x you would need to declare a variable and then use:
SELECT to_char(new_world.nextval)
into world_num;
world := world || world_num;
The immediate syntax error is that assuming NEW_WORLD is a sequence you've created, you would need to do something like
SELECT world ||
cast( new_world.nextval as varchar2(10) )
INTO world
FROM dual;
rather than directly referencing the sequence in your CAST.
It's far from clear to me what your trigger is supposed to be doing though. It is, at a minimum, going to generate an infinite loop. Every INSERT on WORLDS is going to cause the trigger to fire which will generate an INSERT on WORLDS which will cause the trigger to fire, etc. Oracle will eventually raise an error when you exceed the maximum recursion depth. Perhaps you intended this to be a row-level trigger rather than a statement-level trigger that changed the value of :new.world_name? If that's the case, you'd probably want something like
create or replace TRIGGER log_worlds
BEFORE UPDATE OR INSERT ON worlds
FOR EACH ROW
DECLARE
ac VARCHAR2(50);
tab VARCHAR2(50);
world VARCHAR2(50);
BEGIN
IF UPDATING THEN
ac:='Aktualizacja';
END IF;
IF INSERTING THEN
ac:='Nowe';
END IF;
tab:='WORLDS';
world:='world_';
select world || cast(new_world.nextval as varchar2(10)
into world
from dual;
INSERT INTO log(ACTION_DATE,ACTION,TAB_NAME,ADDED_WORLD)
VALUES(SYSDATE,ac,tab,world);
:new.world_name := world;
END;
This assumes that world_name is not actually the primary key. If world_name is the primary key then it would make no sense to modify the primary key value when a row is updated-- you would only want to potentially assign the primary key if you are doing an INSERT.