here I show us what happen when I tried to see if my trigger works.
I have 2 tables: contracts_aux and matches.
team is a NUMBER(1) from 0 to 9.
Attribute team in MATCHES have to be the same of this player in contracts or 1 less or 1 more. (In matches, the same player could appear more than one time).
SQL> select * from contracts_aux;
PLAYER TEAM
-------------------- ----------
Peter 5
Mark 7
SQL> select * from matches;
PLAYER TEAM MATCH
-------------------- ---------- ----------
Peter 5 99
Peter 4 92
SQL> insert into matches values ('Peter',1,41);
insert into matches values ('Peter',1,41)
*
ERROR at line 1:
ORA-20000: error jeje
ORA-06512: at "SYSTEM.MATCHES_BIU_TEAM", line 12
ORA-04088: error during execution of trigger 'SYSTEM.MATCHES_BIU_TEAM'
I obtain that error.
Trigger is:
CREATE TRIGGER MATCHES_BIU_TEAM
BEFORE INSERT OR UPDATE OF team on matches
FOR EACH ROW
DECLARE
nContract_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO nContract_count
FROM CONTRACTS_aux c
WHERE c.PLAYER = :NEW.PLAYER AND
c.TEAM BETWEEN :NEW.TEAM - 1
AND :NEW.TEAM + 1;
IF nContract_count = 0 THEN
RAISE_APPLICATION_ERROR(-20000,'error jeje');
END IF;
END MATCHES_BIU_TEAM;
/
I dont know why appears that error..
Related
Hi so I have am writing a statement to create a trigger in Oracle that would append the text to the description of every new game inserted into the database.
I want the format to be like
Format: (rating). (Name) is (Genre)
Example: M18. Dragon Ball, Genre is Fighting/Adventure.
GenreID and subGenre in Game Table is foreign key to Genre Table.
GameID Sequence
CREATE SEQUENCE "GAME_ID_SEQ" MINVALUE 100 MAXVALUE 999999999
INCREMENT BY 5 START WITH 100;
GameID Trigger
CREATE OR REPLACE TRIGGER "tr_gameID"
BEFORE INSERT ON "GAME"
FOR EACH ROW
BEGIN
SELECT "GAME_ID_SEQ".NEXTVAL INTO :NEW.gameID FROM DUAL;
END;
/
Game Description Trigger
CREATE OR REPLACE TRIGGER "GAME_DES"
BEFORE INSERT OF GAME
FOR EACH ROW
DECLARE
gen VARCHAR2(8);
subGen VARCHAR2(8);
BEGIN
SELECT name INTO gen FROM GENRE WHERE GenreID = :NEW.GenreID;
SELECT name INTO subGen FROM GENRE WHERE subGenreID = :NEW.GenreID;
SELECT CONCAT(rating,".", title ,"Genre is", gen, "/", subGen) INTO :NEW.description FROM DUAL;
END;
/
I'm not sure where I'm doing wrong. But I keep getting "Warning: Trigger created with compilation errors."
What did you do wrong? Several things.
TR_GAMEID is OK (although, could be rewritten as)
SQL> create or replace trigger tr_gameid
2 before insert on game
3 for each row
4 begin
5 :new.gameid := game_id_seq.nextval;
6 end;
7 /
Trigger created.
GAME_DES isn't OK, suffers from various errors.
it isn't before insert OF but ON
the 2nd select refrences subgenreid column from the genre table, but - according to what you posted - such a column doesn't exist in the table (but exists in game)
concat allows only 2 parameters. You'd rather switch to double pipe || concatenation operator.
also, you're concatenating some rating and title things which are unknown. What are they?
The following trigger compiles but is probably wrong as the 2nd select looks suspicious.
SQL> create or replace trigger game_Des
2 before insert on game
3 for each row
4 declare
5 gen varchar2(8);
6 subgen varchar2(8);
7 begin
8 select name into gen from genre where genreid = :new.genreid;
9 select name into subgen from genre where genreid = :new.genreid;
10 :new.description := 'Genre is ' || gen ||'/'|| subgen;
11 end;
12 /
Trigger created.
SQL>
Also, a piece of advice: when Oracle says you got errors, ask it which ones they were. How? Like this (in SQL*Plus) (this is your code):
SQL> CREATE OR REPLACE TRIGGER "GAME_DES"
2 BEFORE INSERT ON GAME --> I fixed this
3 FOR EACH ROW
4 DECLARE
5 gen VARCHAR2(8);
6 subGen VARCHAR2(8);
7 BEGIN
8 SELECT name INTO gen FROM GENRE WHERE GenreID = :NEW.GenreID;
9 SELECT name INTO subGen FROM GENRE WHERE subGenreID = :NEW.GenreID;
10 SELECT CONCAT(rating,".", title ,"Genre is", gen, "/", subGen) INTO :NEW.description FROM DUAL;
11 END;
12 /
Warning: Trigger created with compilation errors.
SQL> show err
Errors for TRIGGER "GAME_DES":
LINE/COL ERROR
-------- -----------------------------------------------------------------
7/3 PL/SQL: SQL Statement ignored
7/10 PL/SQL: ORA-00909: invalid number of arguments
SQL>
Alternatively, query USER_ERRORS:
SQL> select text, line, position
2 from user_errors
3 where name = 'GAME_DES';
TEXT LINE POSITION
-------------------------------------------------- ---------- ----------
PL/SQL: ORA-00909: invalid number of arguments 7 10
PL/SQL: SQL Statement ignored 7 3
SQL>
I have a table:
id
name
amount
If the same name was inserted, then amount should be incremented.
Else, insert with 0 amount.
How to create a trigger with a given condition?
You shouldn't really be doing that. AMOUNT column effectively counts number of NAME appearances in that table. You can always count it, can't you? So, what's the purpose of doing that?
If you want to know which name was inserted prior (or after) some other name (equal to the previous one), sort them by ID (if it is incremental, such as an identity column or if it gets its value from a sequence).
If ID isn't incremental, add DATE_INSERTED column (and sort by it; or apply ROW_NUMBER analytic function which orders values by DATE_INSERTED).
Also, what happens if you delete one of those duplicate names? Will you retroactively decrement AMOUNT column for all previous instances of that NAME?
But, if you insist, here's one option. As you can't just select from a table you're inserting into (because of the mutating table error), I'm using a compound trigger. The part of "insert amount 0" is done by setting the column's default value (you don't need any code for that).
SQL> create table test
2 (id number primary key,
3 name varchar2(20),
4 amount number default 0);
Table created.
SQL> create or replace trigger trg_ai_test
2 for insert on test
3 compound trigger
4
5 type test_rt is record (id test.id%type,
6 name test.name%type);
7 type rli_t is table of test_rt index by pls_integer;
8 g_rli rli_t;
9
10 after each row is
11 begin
12 g_rli(g_rli.count + 1).id := :new.id;
13 g_rli(g_rli.count).name := :new.name;
14 end after each row;
15
16 after statement is
17 l_cnt number;
18 begin
19 for i in 1 .. g_rli.count loop
20 dbms_output.put_Line('x');
21 dbms_output.put_line(i ||' '|| g_rli(i).id ||' '||g_rli(i).name);
22 select count(*) into l_cnt
23 from test
24 where name = g_rli(i).name;
25
26 update test set
27 amount = l_cnt
28 where id = g_rli(i).id;
29 end loop;
30
31 end after statement;
32 end trg_ai_test;
33 /
Trigger created.
SQL>
Testing:
SQL> insert into test (id, name) values (1, 'little');
1 row created.
SQL> insert into test (id, name) values (2, 'foot');
1 row created.
SQL> insert into test (id, name) values (3, 'little');
1 row created.
SQL> insert into test (id, name) values (9, 'little');
1 row created.
SQL> select * from test;
ID NAME AMOUNT
---------- -------------------- ----------
1 little 1
2 foot 1
3 little 2
9 little 3
SQL>
Or, a simpler solution (described above), without using that much code:
SQL> select id, name,
2 row_number() over (partition by name order by id) as amount
3 from test;
ID NAME AMOUNT
---------- -------------------- ----------
2 foot 1
1 little 1
3 little 2
9 little 3
SQL>
I have an Oracle table with 4 columns (Name, Phone, Email, Count).
If the user is updating value of Name column, then I need to increment Count column value by 1.
If the user is updating values other than Name column, then I don't need to increment Count column value by 1.
Initially, when the record is inserted, Count should be 0. And every time when Name column is updated, the Count should be incremented by 1 (like 1, 2, 3 .....).
How we can achieve this? I am very new to databases.
Thanks a lot for your help.
You can do that in an update and insert trigger or in your program. The later however requires all possible programs to cooperate. The former (triggers) is black art.
A program can do it like this:
UPDATE Person SET Count=Count+1, Phone='123' WHERE name=`csr` and Phone <> '123';
This will update one or no record (i.e. if phone was already 123 it will do nothing).
BTW: there is no nice solution to insert it if it was missing.
Hmm, you changed your question, updating the Name is problematic if you do not have another primary key, is that really what you want?
If you are looking at plsql procedure, then you can use this method,
I am using 3 input variables,
1.) column name to edit
2.) old value
3.) New value to be updated
SQL> create or replace procedure updateval (colname varchar2,oldval varchar2,newval varchar2) is
2 l_prop varchar2(10);
3 l_newval varchar2(10);
4 l_old_val varchar2(10);
5 begin
6 l_prop:=colname;
7 l_newval:=newval;
8 l_old_val:=oldval;
9 IF (upper(l_prop)='NAME') THEN
10 update TESTING123 set name=l_newval,count=count+1 where name=l_old_val;
11 elsif (upper(l_prop)='PHONE') THEN
12 update TESTING123 set PHONE=l_newval ,count=count+1where PHONE=l_old_val;
13 elsif (upper(l_prop)='EMAIL') THEN
14 update TESTING123 set EMAIL=l_newval ,count=count+1 where EMAIL=l_old_val;
15 END IF;
16 end;
17 /
Procedure created.
SQL>
SQL> select * from testing123;
NAME PHONE EMAIL COUNT
---------- ---------- ---------- ----------
abc1 12345 ABC#a.COM 1
xyz 3435 xyz#a.COM 0
SQL> exec updateval ('NAME','abc1','newabc1');
PL/SQL procedure successfully completed.
SQL>
SQL>
SQL> select * from testing123;
NAME PHONE EMAIL COUNT
---------- ---------- ---------- ----------
newabc1 12345 ABC#a.COM 2
xyz 3435 xyz#a.COM 0
I am working on a small school project using oracle database. I have created some tables and two of them are Mobile (Mobile_Number,Status_Flag) Status_Flag shows if a number is active or not and there is another table Owner_Mobile(Owner_Id FK,Mobile_ID FK). Now I should write a Constraint that prohibits the insert operation if the corresponding Status_Flag is N for the specified number. I tried to make it using sub query but this is not possible.
the constrain should be applied to OWNER_MOBILE table of course. For example if I say: INSERT INTO OWNER_MOBILE(25541,042536) the constrain should check the Mobile table and see if the Mobile 042536 is active or not . If the number is not active the insert statement should generate a error
You can use the trigger or another PL/SQL API for this but you should take into account ACID transaction principles. Let's consider the case when flag value = 0 should prevent insertion:
SQL> create table mobile (mobile_id int primary key, flag int)
2 /
SQL> create table owner_mobile(owner_id int,
2 mobile_id int references mobile(mobile_id))
3 /
SQL> insert into mobile values (1,1)
2 /
SQL> commit
2 /
SQL> create or replace trigger
2 tr_owner_mobile
3 before insert on owner_mobile
4 for each row
5 declare
6 l_flag mobile.flag%type;
7 begin
8 select flag into l_flag
9 from mobile where mobile_id = :new.mobile_id;
10
11 if l_flag = 0 then
12 raise_application_error(-20000, 'Unavalable mobile');
13 end if;
14 end;
15 /
In the code above I simply select flag and rely on the retrieved value - I don't care of ACID.
In the first transaction I update flag value but don't commit:
SQL> update mobile set flag = 0 where mobile_id = 1;
In the second transaction I insert into owner_mobile and get the success:
SQL> insert into owner_mobile values(1,1);
1 row inserted.
Next, I commit the first transaction and later - the second one. What I get then:
SQL> select * from mobile;
MOBILE_ID FLAG
---------- ----------
1 0
SQL> select * from owner_mobile;
OWNER_ID MOBILE_ID
---------- ----------
1 1
Seems this is not what I expect.
I can use select for update to prevent inconsistent behavoiur:
SQL> update mobile set flag = 1;
1 row updated.
SQL> delete from owner_mobile;
1 row deleted.
SQL> commit;
SQL> create or replace trigger
2 tr_owner_mobile
3 before insert on owner_mobile
4 for each row
5 declare
6 l_flag mobile.flag%type;
7 begin
8 select flag into l_flag
9 from mobile where mobile_id = :new.mobile_id
10 for update;
11
12 if l_flag = 0 then
13 raise_application_error(-20000, 'Unavalable mobile');
14 end if;
15 end;
16 /
Now do the same:
SQL> update mobile set flag = 0 where mobile_id = 1;
1 row updated.
Second transaction is waiting because parent row is locked:
SQL> insert into owner_mobile values(1,1);
After commit in first transaction I get in the second one:
SQL> insert into owner_mobile values(1,1);
insert into owner_mobile values(1,1)
*
error in line 1:
ORA-20000: Unavalable mobile
ORA-06512: at "SCOTT.TR_OWNER_MOBILE", line 9
ORA-04088: error in trigger 'SCOTT.TR_OWNER_MOBILE'
So whatever you do to achieve requirements you will have to consider transaction isolation.
I have 2 tables:
-CONTRACTS(manager,start_date,end_date,cat_num)
-TEAMS(manager,start_date,end_date)
I want to check with a trigger if all managers have a cat_num between 4 and 9 in CONTRACTS when they appear on TEAMS.
That's my trigger:
CREATE TRIGGER T1
BEFORE INSERT OR UPDATE OF manager on teams
FOR EACH ROW
DECLARE
nJP NUMBER;
project_enddate DATE;
BEGIN
SELECT sysdate INTO project_enddate FROM projects WHERE :NEW.end_date IS NULL;
SELECT COUNT(*)
INTO nJP
FROM CONTRACTS c
WHERE c.manager = :NEW.manager AND ((:NEW.start_date<c.start_date AND project_enddate>c.start_date) OR (:NEW.start_date>c.start_date)) AND c.cat_num BETWEEN 4 AND 9;
IF nJP = 0 THEN
RAISE_APPLICATION_ERROR(-20000,'Error: INVALID CAT_NUM');
END IF;
END T1;
/
I check all rows in Contracts which time period is contained on my insertion dates.
I use project_enddate because end_date in projects could be NULL, and I change the value to sysdate (maybe here can be the error) (just below of begin).
When I insert a correct row, my trigger shows me an error during execution and I dont know why. Here a example:
TABLE CONTRACTS
MANAGER START_DA END_DATE CAT_NUM
--------------- -------- -------- ----------
12345 01/10/96 30/09/99 9
12345 01/10/99 30/09/01 8
12345 01/10/01 14/10/04 7
12345 01/02/11 31/01/14 6
12345 01/02/14 6
When I insert into teams values ('12345',to_date('05/02/15','DD-MM-YY'),to_date('29/03/16','DD-MM-YY'))
appears execution error of my trigger:
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "SYSTEM.DISP_CAT_SUP", line 5
ORA-04088: error during execution of trigger 'SYSTEM.DISP_CAT_SUP'