Create a trigger - sql

Create a trigger called NewEntry, that will not allow a result to be inserted into the student exam table if it is less than zero. In your query display a suitable message if the result is less than zero and supply code to test the trigger.
This is what I have done, but I keep getting
warning : trrigger created with compilation errors.
This is my code, please help!
CREATE OR REPLACE TRIGGER NewEntry
AFTER INSERT OR UPDATE ON Assignment2.Student_Exam
FOR EACH ROW
DECLARE
Results NUMBER;
BEGIN
IF(:NEW.Results < '0')
THEN
RAISE_APPLICATION_ERROR
(-20700,'Student's result cannot be less-than ZERO..Enter valid Results':);
ENDIF;
END;
/

END IF, not ENDIF. Also as Jeremy C mentions above you need to create the trigger as BEFORE INSERT OR UPDATE

you listen the other answers but one more thing ,
you must focus on :NEW.Results this is the thing.

There are two errors: Firstly it is 'END IF' not ENDIF, secondly you have apostrophe's in your message.
The correct code is:
CREATE OR REPLACE TRIGGER NewEntry
AFTER INSERT OR UPDATE ON Assignment2.Student_Exam
FOR EACH ROW
DECLARE
Results NUMBER;
BEGIN
IF(:NEW.Results < '0')
THEN
RAISE_APPLICATION_ERROR
(-20700, 'students result cannot be less-than ZERO..Enter valid Results:');
END IF;
END;
/
As others have said you could have de-bugged this yourself by typing show errors; This would have given you the answer e.g.
SQL> show errors;
Errors for TRIGGER NEWENTRY:
LINE/COL ERROR
-------------------------------------------------------------------------
7/18 PLS-00103: Encountered the symbol "S" when expecting one of the
following:
) , * & = - + < / > at in is mod remainder not rem =>
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
edit: In reply to Ersin - If it was New.Results then you would get a bind error e.g.
SQL> show errors;
Errors for TRIGGER NEWENTRY:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/4 PLS-00049: bad bind variable 'NEW.RESULTS'
SQL>
This will be a result of 'RESULTS' not being a column in Student_Exam, which I presume does exist given the rest of the statement.

Related

Function - oracle (PLS-00103: Encountered the symbol "")

I'm trying to create a simple oracle function which loops over some records and then inserts records for each of those ..
CREATE OR REPLACE FUNCTION addNewRolesToAllGDP
return NUMBER
is dummy number;
BEGIN
FOR applicationId IN (SELECT APPID
FROM GRPAPPLICATIONINSTANCES
where GRPAPPID = (select GRPAPPID
from GRPAPPLICATIONS
where GRPNAME = 'DIGITAL_OFFICE')
AND APPID in (select APPID from APPLICATIONS where REGEXP_LIKE(APPNAME, '[[:digit:]]')))
LOOP
INSERT INTO ROLES (ROLID, ROLNAME, APPID)
VALUES (SEQROLES.nextval,
'INVENTORY_REQUESTER',
applicationId);
INSERT INTO ROLES (ROLID, ROLNAME, APPID)
VALUES (SEQROLES.nextval,
'INVENTORY_OWNER',
applicationId);
INSERT INTO ROLES (ROLID, ROLNAME, APPID)
VALUES (SEQROLES.nextval,
'INVENTORY_ADMIN',
applicationId);
END LOOP;
RETURN 1;
END;
alter function addNewRolesToAllGDP compile;
This statements gives me the following in USER_ERRORS:
PLS-00103: Encountered the symbol "" when expecting one of the following: ( return compress compiled wrapped
I'm not sure if this is the problem, but I notice that you do not have a slash following the END statement of the function. In Oracle tools, without that slash, the statement does not actually get terminated, and the ALTER command is included as part of the same statement. This can cause weird syntax errors.
If this is the problem, fundamentally this question is a duplicate of oracle SQL plus how to end command in SQL file?.
Edited to add As others have said in comments, the same code seems to compile fine for me when I cut-and-paste it from your post. Based on the error and the position where it is reported, my best guess is that at the end of the first line your original source has some invisible character that is causing the parser error.
Used to run this in Intellij which gave me the stated behaviour. After running it from sqlDeveloper it compiled fine.
I got a similar error message for a missing comma in the procedure definition and got compiled after adding the comma.
Procedure definition before fix
PROCEDURE CREATE_WO(p_wo_type IN NUMBER,
p_id IN NUMBER,
p_do_commit IN VARCHAR2 DEFAULT 'Y'
p_return_value OUT VARCHAR2)
IS
BEGIN
...
END;
Error Message
Cause: java.sql.SQLException: ORA-06550: line 8, column 9:
PLS-00103: Encountered the symbol "" when expecting one of the following:
) , * & = - + < / > at in is mod remainder not rem =>
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
Procedure definition after fix, note the comma at the end of p_do_commit
PROCEDURE CREATE_WO(p_wo_type IN NUMBER,
p_id IN NUMBER,
p_do_commit IN VARCHAR2 DEFAULT 'Y',
p_return_value OUT VARCHAR2)
IS
BEGIN
...
END;

Error(6,87): PLS-00103: Encountered the symbol "JOIN" when expecting one of the following/compound trigger

When I try to compile below compound trigger I got the error message. Please suggest what can be done to clear those error.
I tried to use normal trigger but its throwing ORA-04091 ERROR.
create or replace TRIGGER "WS5108"."AL_PROJECT_ORACLE_CODE_TRG" FOR
INSERT
ON ITIB_REQUESTS
COMPOUND TRIGGER
DECLARE
V_CODE varchar (200);
BEGIN
IF :NEW."J_PROJECT_ORACLE_CODE" IS NULL THEN
SELECT distinct (PROJECT_ORACLE_CODE) INTO V_CODE
FROM ITIB_PROJECT_ORACLE_CODE POC
JOIN ITIB_VPDOMAIN VP ON (POC.VP_DOMAIN = VP.VP_DOMAIN)
WHERE POC.VP_DOMAIN = (SELECT VP_DOMAIN
FROM ITIB_VPDOMAIN
WHERE ID = :NEW."VP_DOMAIN")
AND CAPEX_CATEGORY = :NEW."C_CAPEX_CATEGORY"
AND :NEW."C_TOTAL_EURO" <= 250 ;
END IF;
:NEW.J_PROJECT_ORACLE_CODE := V_CODE;
EXCEPTION
when no_data_found then
V_CODE := null ;
END AL_PROJECT_ORACLE_CODE_TRG;
I am trying to add value for one column in table after new line inserted in that table if that column is empty. This column value I am taking from that select condition and new values which are inserted in table.
The error in your question title is the second of two; running the reformatted code in your question I see:
LINE/COL ERROR
--------- -------------------------------------------------------------
2/1 PLS-00103: Encountered the symbol "DECLARE" when expecting one of the following: function pragma procedure subtype type <an identifier> <a double-quoted delimited-identifier> current cursor delete exists prior before after instead
8/9 PLS-00103: Encountered the symbol "JOIN" when expecting one of the following: , ; for group having intersect minus order start union where connect
(with different line number due to reformatting). In general you should fix the first error reported first, as subsequent errors are often unhelpful and caused by side-effects of the earlier ones. That is the case here. If you fix the compound trigger syntax to address the error reported against DECLARE then the JOIN is no longer a problem either:
create or replace TRIGGER "WS5108"."AL_PROJECT_ORACLE_CODE_TRG"
FOR INSERT
ON ITIB_REQUESTS
COMPOUND TRIGGER
BEFORE EACH ROW IS
V_CODE varchar (200);
BEGIN
IF :NEW."J_PROJECT_ORACLE_CODE" IS NULL THEN
SELECT distinct PROJECT_ORACLE_CODE INTO V_CODE
...
END IF;
:NEW.J_PROJECT_ORACLE_CODE := V_CODE;
EXCEPTION
when no_data_found then
V_CODE := null ;
END BEFORE EACH ROW;
END AL_PROJECT_ORACLE_CODE_TRG;
/
Basically, the main trigger body code you had needed to be in a BEFORE EACH ROW block, since it is a compound trigger.
Incidentally, you probably want V_CODE to be declared as varchar2 rather than varchar, or as ITIB_PROJECT_ORACLE_CODE.PROJECT_ORACLE_CODE%TYPE. If you need that variable at all; the assignment back to the :NEW field probably wants to be inside the IF block (as if that is not initially null, you set it to v_code, which is then null!), but you can also select straight into the :NEW variable. So I think you really want something more like:
create or replace TRIGGER WS5108.AL_PROJECT_ORACLE_CODE_TRG
FOR INSERT
ON ITIB_REQUESTS
COMPOUND TRIGGER
BEFORE EACH ROW IS
BEGIN
IF :NEW.J_PROJECT_ORACLE_CODE IS NULL THEN
SELECT PROJECT_ORACLE_CODE
INTO :NEW.J_PROJECT_ORACLE_CODE
FROM ITIB_PROJECT_ORACLE_CODE POC
JOIN ITIB_VPDOMAIN VP ON (POC.VP_DOMAIN = VP.VP_DOMAIN)
WHERE POC.VP_DOMAIN = (SELECT VP_DOMAIN
FROM ITIB_VPDOMAIN
WHERE ID = :NEW."VP_DOMAIN")
AND CAPEX_CATEGORY = :NEW.C_CAPEX_CATEGORY
AND :NEW.C_TOTAL_EURO <= 250 ;
END IF;
EXCEPTION
when no_data_found then
null ; -- do nothing; :NEW.J_PROJECT_ORACLE_CODE is already null
END BEFORE EACH ROW;
END AL_PROJECT_ORACLE_CODE_TRG;
/
I don't really see why this needs to be a compound trigger though, you aren't accessing the table the trigger is against (as you were in your previous question) and you only have a single scenario - only before insert; so a simple trigger would work here:
create or replace WS5108.TRIGGER AL_PROJECT_ORACLE_CODE_TRG
BEFORE INSERT
ON ITIB_REQUESTS
FOR EACH ROW
BEGIN
IF :NEW.J_PROJECT_ORACLE_CODE IS NULL THEN
SELECT PROJECT_ORACLE_CODE
INTO :NEW.J_PROJECT_ORACLE_CODE
FROM ITIB_PROJECT_ORACLE_CODE POC
JOIN ITIB_VPDOMAIN VP ON (POC.VP_DOMAIN = VP.VP_DOMAIN)
WHERE POC.VP_DOMAIN = (SELECT VP_DOMAIN
FROM ITIB_VPDOMAIN
WHERE ID = :NEW.VP_DOMAIN)
AND CAPEX_CATEGORY = :NEW.C_CAPEX_CATEGORY
AND :NEW.C_TOTAL_EURO <= 250 ;
END IF;
EXCEPTION
when no_data_found then
null ; -- do nothing; :NEW.J_PROJECT_ORACLE_CODE is already null
END AL_PROJECT_ORACLE_CODE_TRG;
/
And even the query within that looks confused; you don't need the subquery:
...
SELECT PROJECT_ORACLE_CODE
INTO :NEW.J_PROJECT_ORACLE_CODE
FROM ITIB_PROJECT_ORACLE_CODE POC
JOIN ITIB_VPDOMAIN VP ON (POC.VP_DOMAIN = VP.VP_DOMAIN)
WHERE VP.ID = :NEW.VP_DOMAIN
AND CAPEX_CATEGORY = :NEW.C_CAPEX_CATEGORY
AND :NEW.C_TOTAL_EURO <= 250 ;
...

Issue with trigger for archiving

Trying to make a trigger that puts data into an archive table when a column called COMPLETION_STATUS goes from incomplete to complete, the dbms is a placeholder for the insert but I'm getting the following errors in the if statement
Error(6,1): PLS-00103: Encountered the symbol enter code here"SELECT" when expecting one of the following: begin function pragma procedure subtype type current cursor delete exists prior The symbol "begin" was substituted for "SELECT" to continue.
Error(9,1): PLS-00103: Encountered the symbol "IF" when expecting one of the following: * & - + ; / at for mod remainder rem and or group having intersect minus order start union where connect || multiset The symbol ";" was substituted for "IF" to continue.
Error(13,4): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Code:
create or replace TRIGGER ARCHIVING_TRIG
BEFORE UPDATE OF COMPLETION_STATUS ON PROJECT_DATA
BEGIN
DECLARE COMPLETION_STATUS1 VARCHAR2(9);
SELECT COMPLETION_STATUS into COMPLETION_STATUS1
FROM PROJECT_DATA WHERE COMPLETION_STATUS = 'complete'
IF COMPLETION_STATUS1 = 'complete'
THEN
DBMS.output('123');
END IF;
END;
The DECLARE block should be before the BEGIN block.
The SELECT ... statement needs to be terminated with a semicolon (;).
It's dbms_output.put_line() not dbms.output();
You're trying to assign the result of a query that potentially can return more than one row to a scalar variable.
The rows selected from project_data have no relation to the one(s) that triggered the trigger.
I suggest you use something like:
CREATE TRIGGER archiving_trig
AFTER UPDATE
ON project_data
FOR EACH ROW
WHEN (old.completion_status <> 'complete'
AND new.completion_status = 'complete')
BEGIN
dbms_output.put_line('Trigger fired for ID ' || :new.id);
END;
db<>fiddle
I think maybe AFTER is the better time, because you want to archive the row after the status was successfully changed.
Because of the WHEN the trigger will only fire if completion_status has been changed from something other than 'complete' to 'complete'. But you maybe also need to have a method of removing entries from the archive when the status changes from 'complete' to something else. That isn't covered here.
Declaring it as FOR EACH ROW let's you access the values of the updated row via :new. That way you don't need a query to select that nor a variable to select into.
I guess you need this:
create table PROJECT_DATA_NEW as select * from PROJECT_DATA where 1=2;
CREATE OR REPLACE TRIGGER ARCHIVING_TRIG
AFTER UPDATE
ON PROJECT_DATA
FOR EACH ROW
DECLARE
status number;
BEGIN
status:=0;
select 1 into status from PROJECT_DATA where
:new.COMPLETION_STATUS='complete' and
:old.COMPLETION_STATUS='incomplete'
if (status=1) then
insert into PROJECT_DATA_NEW values(:old.column1,
:old.column2,
:old.column3,
:old.column4,
:old.column5,....etc);
end if;
END;
/

pl/sql trigger error : exact fetch returns more than requested number of rows

I am having a tough time understanding what is wrong with my pl/sql trigger.
The error is :
Error report -
SQL Error: ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "SYSTEM.TRG_LATE_RETURN", line 6
ORA-04088: error during execution of trigger 'SYSTEM.TRG_LATE_RETURN'
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
My trigger is as follows:
create or replace trigger trg_late_return
before update of DETAIL_RETURNDATE, DETAIL_DUEDATE on TY_DETAILRENTAL
declare
temp_date DATE:= SYSDATE;
temp_due_date DATE:= SYSDATE;
BEGIN
select DETAIL_RETURNDATE
into temp_date
from TY_DETAILRENTAL;
select DETAIL_DUEDATE
into temp_due_date
from TY_DETAILRENTAL;
IF temp_date is null
THEN
update TY_DETAILRENTAL
set DETAIL_DAYSLATE=null;
END IF;
if temp_date <> null
THEN
if temp_date = trunc(temp_due_date) + 1
then
update TY_DETAILRENTAL
set DETAIL_DAYSLATE=0;
end if;
if temp_date > trunc(temp_due_date) + 1
then
update TY_DETAILRENTAL
set DETAIL_DAYSLATE = DETAIL_RETURNDATE - DETAIL_DUEDATE;
end if;
end if;
END;
/
New to SQL and PL/SQL so I would appreciate any help.
None of your queries or updates have filters (where clauses) so you are working on the entire table - that can't be what you intended. You are trying to get all of the value of those columns into scalar variables, which can only hold a single value.
The trigger is also against the same table you're querying and updating, which suggests you actually meant this to be (or need this to be) a row level trigger, not a statement level trigger.
That means you need to add for each row to the definition, and instead of requerying and updating the table, you can operate on the new pseudorecord that is available for row level triggers.
You also can't use <> to compare with null; you're already using is null, and the opposite of that is is not null. Although you could also just use else here.
So this might be what you wanted:
create or replace trigger trg_late_return
before update of detail_returndate, detail_duedate
on ty_detailrental
for each row
begin
if :new.detail_returndate is null
then
:new.detail_dayslate := null;
else
if :new.detail_returndate = trunc(:new.detail_duedate) + 1
then
:new.detail_dayslate := 0;
elsif :new.detail_returndate > trunc(:new.detail_duedate) + 1
then
:new.detail_dayslate := :new.detail_returndate - :new.detail_duedate;
end if;
end if;
end;
/
You can refer to the updated columns value with :new when comparing them too, so you don't need the local variable copies of those values. (You can look at the pre-update values with :old too, but that doesn't seem to be needed here).
Changes you make to the new pseudorecord are used when the actual matching row in the database is finally updated.
Read more about the new/old pseudorecords, and about triggers in general.

Oracle Trigger create with compilation errors

I wrote the below trigger to prevent users from allocating a Class to a Session if the Class Date does not match the day of the week the Session is on.
CREATE OR REPLACE TRIGGER trig_alternative_classDate
AFTER INSERT OR UPDATE ON ALTERNATIVE
FOR EACH ROW
DECLARE
classdate CHAR;
sessionday VARCHAR;
BEGIN
SELECT to_char(to_date(class.class_date), 'Day') INTO classdate, sessions.day INTO sessionday
FROM SESSIONS, CLASS, DUAL, LOCATION, ALTERNATIVE
WHERE class.class_id = alternative.class_id
AND alternative.location_id = location.location_id
AND sessions.location_id = location.location_id;
IF sessions.day != to_char(to_date(class.class_date), 'Day')
THEN raise_application_error(-20999,'Invalid Class Date - Class Date does not match Session Day');
END IF;
END;
/
However I get an error message when I run the trigger
Warning: Trigger created with compilation errors.
SQL> show error trigger trig_alternative_classDate
Errors for TRIGGER TRIG_ALTERNATIVE_CLASSDATE:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/2 PL/SQL: SQL Statement ignored
5/80 PL/SQL: ORA-00923: FROM keyword not found where expected
Could someone please help?
Remove second INTO - only one INTO is needed:
INTO classdate, sessions.day INTO sessionday