Simple trigger in sql - sql

I am creating triggers for my project. I have a table stadium with its capacity and table match with number of viewers. I want to check if number of viewers isn't bigger than capacity and this error pops up.
The trigger 'CzyPojemnoscWidownia - Mecz (DBA)' could not be modified in the database.
Syntax error near 'IF' on line 11
[Sybase][ODBC Driver][SQL Anywhere]Syntax error near 'IF' on line 11
SQLCODE: -131
SQLSTATE: 42000
That's my code, it's sybase anywhere sql
ALTER TRIGGER "czyPojemnosc" BEFORE INSERT
ORDER 1 ON "DBA"."Mecz"
REFERENCING NEW AS nowy
FOR EACH ROW
When
(Hala.IdH=nowy.IdH)
BEGIN
SELECT nowy.Widownia, Hala.Pojemnosc
FROM nowy
Inner join Hala on nowy.IdH=Hala.IdH
IF nowy.Widownia > Hala.Pojemnosc
THEN
RAISERROR 30005 'Wprowadzona liczba widzów jest większa niż pojemność sali'
END IF;
END
first I am comparing Id to point which stadium is it, then joining tables and checking if it's not bigger
I need it to display error when there is an attempt to put in stadium more people than it's capable to store

Related

Why am I receiving the PSL-00103 Error in Oracle SQL?

I am trying to make a procedure that would insert a row into a table in Oracle SQL. However, I can't figure out a solid reason on why this issue exists when I write any type of procedure.
I have tried changing the syntax around a couple of times, but I still don't know how to remedy the issue.
Errors given:
Error at line 1: PLS-00103: Encountered the symbol ")" when expecting one of the following: in out table ... columns long double ref char time timestamp interval date binary national character nchar
Error at line 5: PL/SQL: SQL Statement ignored Error at line 6: PL/SQL: ORA-00984: column not allowed here
Code:
create or replace procedure insert_category(
category_name_param in categories.category_name%type)
as
begin
insert into categories (category_id, category_name)
values (category_id, category_name_param);
end;
It seems that procedure lacks in yet another parameter; see if this helps (I presumed that such a column exists in the table; can't be sure as you didn't post table description):
create or replace procedure insert_category(
category_name_param in categories.category_name%type,
category_id_param in categories.category_id%type --> this
)
as
begin
insert into categories
(category_id,
category_name)
values
(category_id_param, --> this
category_name_param);
end;

Creating a trigger that will update an attribute

Question: write a trigger that will update the invoice subtotal each time the line table is updated (a new row inserted, updated or deleted). Include the SQL statements used to test the insert, update and delete.
I'm finding it difficult to properly understand triggers and I don't know why. I understand the basic concept of it (at least I think I do) but I can't seem to understand how to answer my question. The following code is my attempt at answering the above question:
create or replace trigger update_subtotal
after insert or update or delete
on invoice
for each row
begin
insert into line ('inv_number', 'line_number', 'p_code', 'line_units', 'line_price')
values ('1009', '3', '12345-6t', '1', '123.45');
end;
select * from line;
After running this code I ended up with these errors:
Errors: TRIGGER UPDATE_SUBTOTAL
Line/Col: 3/1 PL/SQL: SQL Statement ignored
Line/Col: 3/19 PL/SQL: ORA-00928: missing SELECT keyword
Line/Col: 17/1 PLS-00103: Encountered the symbol "SELECT"
I'm using Oracle Live.
In short: help.
You seem to have the concept backwards. The invoice table needs to be updated when line changes -- so line needs the trigger and the change to invoice is an update. That would be something like this:
create or replace trigger trg_line_update_subtotal
after insert or update or delete
on line
for each row
begin
update invoice i
set total = coalesce(i.total, 0) +
coalesce(:new.line_Units * :new.line_price, 0) -
coalesce(:old.line_Units * :old.line_price, 0)
where i.inv_number = coalesce(:new.inv_number, :old.inv_number);
end;

Audit Table Trigger

Trying to create a trigger for populating an audit table with old data before changes are made to the base table BOOKS
CREATE OR REPLACE TRIGGER populate_audit_table
BEFORE INSERT OR UPDATE OF cost, retail OR DELETE
ON books
REFERENCING NEW as new OLD as old
FOR EACH ROW
DECLARE
dml_operation varchar2(1) :=
CASE WHEN UPDATING THEN 'U'
WHEN DELETING THEN 'D'
ELSE 'I'
END;
BEGIN
INSERT INTO cost_retail_history
(isbn
,title
,pubid
,pubdate
,cost
,retail
,discount
,category
,dml_operation)
SELECT
(old.isbn
,old.title
,old.pubid
,old.pubdate
,old.cost
,old.retail
,old.discount
,old.category
,new.dml_operation)
FROM BOOKS;
end;
I get the following errors:
Errors: TRIGGER POPULATE_AUDIT_TABLE
Line/Col: 8/7 PL/SQL: SQL Statement ignored
Line/Col: 20/13 PL/SQL: ORA-00907: missing right parenthesis
I also tried using VALUES on the INSERT INTO and not designating a source table ("FROM BOOKS")
....VALUES
(old.isbn
,old.title
,old.pubid
,old.pubdate
,old.cost
,old.retail
,old.discount
,old.category
,new.dml_operation);
end;
And I get the following errors:
Line/Col: 8/7 PL/SQL: SQL Statement ignored
Line/Col: 27/18 PL/SQL: ORA-00984: column not allowed here
I've read and re-read https://docs.oracle.com/cd/A64702_01/doc/server.805/a58225/ch4a.htm#1997457 so I feel like I'm missing something simple and just need a point in the right direction.
Thanks,
EDIT:
I dropped the dml_operation as this wasn't required and followed the advice below, but I am still getting errors:
Current version:
CREATE OR REPLACE TRIGGER cost_retail_history
BEFORE INSERT
OR UPDATE OF cost, retail
OR DELETE
ON books
REFERENCING NEW as new OLD as old
FOR EACH ROW
BEGIN
CASE
WHEN INSERTING THEN
INSERT INTO cost_retail_history
(isbn
,title
,pubid
,pubdate
,cost
,retail
,discount
,category)
VALUES
(:new.isbn
,:new.title
,:new.pubid
,:new.pubdate
,:new.cost
,:new.retail
,:new.discount
,:new.category)
WHEN UPDATING cost, retail OR DELETING THEN
INSERT INTO cost_retail_history
(isbn
,title
,pubid
,pubdate
,cost
,retail
,discount
,category)
VALUES
(:old.isbn
,:old.title
,:old.pubid
,:old.pubdate
,:old.cost
,:old.retail
,:old.discount
,:old.category);
END CASE;
END;
I'm getting the errors:
Errors: TRIGGER COST_RETAIL_HISTORY
Line/Col: 4/9 PL/SQL: SQL Statement ignored
Line/Col: 22/5 PL/SQL: ORA-00933: SQL command not properly ended
I can't tell exactly what line the error is on as this would indicate it's with:
...OR DELETE
and
... ,:new.title
which does not make sense to me.
If you were doing insert ... select ... then you should not have the parentheses around the column list; i.e.:
INSERT INTO cost_retail_history
(isbn
...
,dml_operation)
SELECT
old.isbn
...
,new.dml_operation
FROM BOOKS;
but you should not be selecting from the table the trigger is against - partly because you'll get a mutating table error, and you are attempting to insert an audit row for every row in the base table; but mostly because you already have all of the information you need.
With the values clase you need to prefix the old/new values with a colon:
....VALUES
(:old.isbn
,:old.title
,:old.pubid
,:old.pubdate
,:old.cost
,:old.retail
,:old.discount
,:old.category
,:new.dml_operation);
end;
Read more in the documentation.
Oracle has built-in audit tools but presumably this is an exercise.
I can't tell exactly what line the error is on as this would indicate...
This can be slightly confusing with triggers as they are a mix of SQL and PL/SQL. Because you are getting PL/SQL errors the line numbering starts from the beginning of the PL/SQL part, so here BEGIN is line 1, INSERT is line 4; WHEN UPDATING... is line 22.
Those new errors are just because you don't have a semicolon at the end of the first INSERT statement:
,:new.discount
,:new.category);
-----------------------^
WHEN UPDATING cost, retail OR DELETING THEN
INSERT INTO cost_retail_history
The error is reported against line 22 because that WHEN is where it's expecting to see the semicolon, and the first point it can see the previous SQL command hasn't been completed. The error against line 4 is saying where that not-ended command started; so you're getting two messages for one actual problem.

Creating a trigger with SELECT Function

Good day everyone,
I'm having trouble making my trigger work. As far as the functionality of the body and how it behaves, it does exactly as I intended for it to behave. However, when I start to fire the trigger, it returns an error in which Triggers should not have a SELECT statement from inside the main body. I'm still fairly new to coding and how to materialize the idea in my head into code. Hopefully someone could point me in a right direction on how change the Trigger I would like to have as a final result. Please see below script.
Update: Expected result would be whenever a user UPDATE a row and INSERT a new record via the application or job being run in the background, S1_HOVER_REPORT column would be updated with the value from the SELECT script and use the data from the S1_HOVER case result.
(Edit: I have updated the details of the problem above, added the Table being used and Error return)
Table: SITE
Column Name Type
------------------------------
ID VARCHAR2(14)
NAME VARCHAR2(70)
TYPE_CODE VARCHAR2(2)
PARENT VARCHAR2(14)
S1_HOVER_REPORT VARCHAR2(14)
CREATE OR REPLACE TRIGGER MESS.S1_HOVER_REPORT
AFTER INSERT OR UPDATE ON MESS.SITE
FOR EACH ROW
BEGIN
UPDATE (SELECT S1.ID,
S1.NAME,
S1.TYPE_CODE,
S1.PARENT AS PARENT1,
S2.PARENT AS PARENT2,
S1.S1_HOVER_REPORT,
CASE
WHEN (S1.TYPE_CODE = 'H2') THEN S1.PARENT
WHEN (S1.TYPE_CODE = 'S1') THEN S2.PARENT
ELSE S1.ID
END AS S1_HOVER
FROM SITE S1,
(SELECT ID,
NAME,
PARENT,
TYPE_CODE
FROM site
WHERE type_code='H2') S2
WHERE S1.PARENT=S2.ID
OR S1.ID = S2.PARENT) S3
SET S3.S1_HOVER_REPORT = S3.S1_HOVER;
END;
Error returned when Trigger fired:
Error report -
SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table
ORA-06512: at "MES.S1_HOVER_REPORT", line 2
ORA-04088: error during execution of trigger 'MES.S1_HOVER_REPORT'
01779. 00000 - "cannot modify a column which maps to a non key-preserved table"
*Cause: An attempt was made to insert or update columns of a join view which
map to a non-key-preserved table.
*Action: Modify the underlying base tables directly.
(Update: I have included the updated trigger and it's now compiling without any issue, but I'm having errors whenever I try updating a record)
CREATE OR REPLACE TRIGGER MESS.S1_HOVER_REPORT
BEFORE INSERT OR UPDATE ON MESS.SITE
FOR EACH ROW
DECLARE
v_S1_HOVER_REPORT VARCHAR2(14);
BEGIN
SELECT CASE
WHEN (S1.TYPE_CODE = 'H2') THEN S1.PARENT
WHEN (S1.TYPE_CODE = 'S1') THEN S2.PARENT
ELSE (S1.ID)
END AS S1_HOVER
INTO v_S1_HOVER_REPORT
FROM SITE S1,
(SELECT ID,
NAME,
PARENT,
TYPE_CODE
FROM site
WHERE type_code='H2') S2
WHERE S1.PARENT=S2.ID
OR S1.ID = S2.PARENT;
:NEW.S1_HOVER_REPORT := v_S1_HOVER_REPORT;
END;
Error report -
SQL Error: ORA-04091: table MES.SITE is mutating, trigger/function may not see it
ORA-06512: at "MES.S1_HOVER_REPORT", line 4
ORA-04088: error during execution of trigger 'MES.S1_HOVER_REPORT'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
Firstly from the error message
An attempt was made to insert or update columns of a join view which map to a non-key-preserved table.
S3 is the veiw ( you are creating the view by doing a select inside an update statment). You can try and change this to have key preservation but I really wouldn't know how.
The error suggests updating the base tables not the view. So as mentioned in the comments :old and :new are your friend.
:OLD holds all the values of the table the trigger is created on BEFORE the update (null if insert)
:NEW holds all the values of the table the trigger is created on AFTER the update / insert.....
So if I understand what you want to do correctly you would need to...
declare a variable eg v_S1_hover_report
do your select returning whatever value you need into this variable
set the value in your site table by doing
:NEW.S1_HOVER_REPORT := v_S1_hover_report
By setting this value into the :NEW object when a commit happens it will be committed to the database. This completely removes the need for an update statement in the trigger.
You can also use :NEW.id in your select statement to filter it down to the record you are updating if it is helpfull
CREATE OR REPLACE TRIGGER MESS.S1_HOVER_REPORT
AFTER INSERT OR UPDATE ON MESS.SITE
FOR EACH ROW
v_test varchar2(10);
BEGIN
select 'Your value' into v_test from dual;
:new.s1_hover_report := v_test;
END;
OR
CREATE OR REPLACE TRIGGER MESS.S1_HOVER_REPORT
AFTER INSERT OR UPDATE ON MESS.SITE
FOR EACH ROW
v_test varchar2(10);
BEGIN
select 'Your value' into :new.s1_hover_report from dual;
END;

Trigger does not allow any inserts

I have written a trigger that does not allow more than two 'Full' ranked professors as part of the faculty (For example, trigger should fire if a new (third) Full professor is added or rank is updated to Full for one of the existing Associate professors.)
It does compile but does not let me know add any data to my table at all. It only needs to be used once. Do I use the statement level trigger for this?
Also, at the moment it does not let me update or insert Professor Rank at all, whether its Full or Associate. How would I fix that?
I have also been told that before/after and that my logic of comparison is wrong. Please help!
Here is the trigger:
CREATE OR REPLACE TRIGGER TRG_PROF_RANK
after insert or update of F_RANK
on FACULTY
DECLARE
FULL_RANK_COUNT integer;
MAX_FULL_RANK_COUNT number :=2;
begin
select count(*) into FULL_RANK_COUNT
from FACULTY
where F_RANK ='Full';
if FULL_RANK_COUNT < MAX_FULL_RANK_COUNT
then
return;
else
if (FULL_RANK_COUNT >= MAX_FULL_RANK_COUNT) then
RAISE_APPLICATION_ERROR (-20000, 'Can only have 2 professors with ranking "Full".');
end if;
end if;
end;
/
I test it with the following statement:
insert into FACULTY values(6, 'John', 'Bonny', 'M', 13, '4079347153', 'Associate', 80000, 2, 6034, Null);
But it doesn't allow me to insert any records into the table. And this is the error that I get:
Error starting at line : 240 in command -
insert into FACULTY values(6, 'John', 'Bonny', 'M', 13, '4079347153', 'Associate', 80000, 2, 6034, Null)
Error report -
SQL Error: ORA-20000: Can only have 2 professors with ranking "Full".
ORA-06512: at "IT337104.TRG_PROF_RANK", line 16
ORA-04088: error during execution of trigger 'IT337104.TRG_PROF_RANK'
20000. 00000 - "%s"
*Cause: The stored procedure 'raise_application_error'
was called which causes this error to be generated.
*Action: Correct the problem as described in the error message or contact
the application administrator or DBA for more information.
please help, I just to make sure I can insert data.
Thank you
The query should raise a mutating table error so the trigger shouldn't be executing at all. You cannot query a table from within a trigger written on that table. You must either maintain the count of full professorships elsewhere or perform the test in your application code before issuing the insert or update. This is a problem with any data integrity check that depends on data in other rows of the same table, other than, of course, a UNIQUE constraint. It simply can't be done from within a trigger on that table.
But even if you could, you have a major logic error. If your table already contains two full professors, this trigger would prevent all Inserts and Updates on the table, even if they did not involve full professors.
But all is not lost. If you fix the logic flaw, turn the trigger into a before trigger for each row, examine the contents of :new.F_RANK and act accordingly, one solution you may want to look into can be found here: Oracle; limit rows per column value. (The second answer with the materialized view, not the first.)