I have two triggers. One trigger for UPDATE and INSERT and one trigger for DELETE.
create or replace
TRIGGER insup_trigger
BEFORE INSERT OR UPDATE ON USER_GROUPS
FOR EACH ROW
BEGIN
UPDATE PROJECTS
SET TOUCHED = 1
WHERE ID IN (SELECT PJ_ID
FROM PROJECT_ROLES_GROUPS
WHERE GRP_ID = :NEW.GRP_ID);
END;
and the trigger for delete:
create or replace
TRIGGER MARK
BEFORE DELETE ON USER_GROUPS
FOR EACH ROW
BEGIN
UPDATE PROJECTS
SET TOUCHED = 1
WHERE ID IN (SELECT PJ_ID
FROM PROJECT_ROLES_GROUPS
WHERE GRP_ID = :OLD.GRP_ID);
END;
Now these triggers work fine a few times but after that the errors are thrown
ORA-01013: user requested cancel of current operation
ORA-06512: at "MARK", line 3
ORA-04088: error during execution of trigger 'MARK'
Triggering the triggers from SQL Developer by doing manual insert and delete does not trigger the error, this error appears from an .net applications that does the inserts and deletes.
Am I missing something ?
EDIT:
Reading the comments I got the hint that the problem might be in the vb.net code. I had:
adTrans = ADOCon.BeginTransaction()
adCMD = New OdbcCommand(vsSQL, ADOCon)
adCMD.Transaction = adTrans
Try
adCMD.ExecuteNonQuery()
adTrans.Commit() <- here is the error it should be
-> adCMD.Transaction.Commit()
Return True
Catch ex As Exception
' Try to rollback the transaction
Try
adTrans.Rollback()
If vbSuppressOutput = False Then
MsgBox(ex.Message)
End If
System.Threading.Thread.Sleep(20)
Catch
' Do nothing here; transaction is not active.
End Try
Return False
End Try
So I tried with the modified code and I cannot reproduce the problem anymore.
Thank you very very very much for your spot on comments!
The edit of the question is wrong.
As the comments suggested the problem was that I did not commit the transactions done with SQL Developer.
Because of that the transactions done with the VB.net application were unable to complete and the errors were generated.
Related
I'm trying to get the suspension value in my studentstaff table to change from 'no' to 'yes' when the fine (a separate table) amount reaches >=10 for a specific person. I've also tried using IF but nothings seems to be working as I keep getting this error: ORA-04079: invalid trigger specification. "amount NUMBER(8);" is in the code as it was asking me to declare amount. I am using Oracle SQL. Thanks in advance.
CREATE TRIGGER new_suspension
AFTER UPDATE ON fine
FOR EACH ROW
amount NUMBER(8);
BEGIN
CASE
WHEN Amount >= 10 THEN
UPDATE studentstaff
SET suspensions = 'yes'
WHERE library_card_no = '419746';
END CASE;
END;
/
The best option for this type of trigger is to use the when condition on trigger as follows:
CREATE OR REPLACE TRIGGER new_suspension
AFTER UPDATE ON fine
FOR EACH ROW
WHEN (NEW.AMOUNY >= 10)
BEGIN
UPDATE studentstaff
SET suspensions = 'yes'
WHERE library_card_no = :new.LIBRARY_CARD_HOLDER;
END;
/
This trigger will be executed when the condition written in the WHEN clause is satisfied.
Without seeing your table definitions its hard, but here's a guess at what you might need
CREATE OR REPLACE
TRIGGER new_suspension
AFTER UPDATE ON fine
FOR EACH ROW
BEGIN
if :new.Amount >= 10 THEN -- ie, the incoming AMOUNT on the FINE table
UPDATE studentstaff
SET suspensions = 'yes'
WHERE library_card_no = :new.LIBRARY_CARD_HOLDER -- ie, the STUDENT being fined
end if;
END;
/
Hopefully that makes sense and is close to what you're aiming to achieve here. In this example, I'm assuming that your FINE table, contains the amount and the library card holder (ie, the student etc)
I want my trigger to determined that ApprUserNo = SubmitUserNo or OrgParentNo. Here's my trigger so far :
CREATE OR REPLACE TRIGGER cteam_Trigger1
BEFORE INSERT OR UPDATE OF ApprUserNo
ON cteam_ExpenseReport
FOR EACH ROW
DECLARE
ApprOrgNo cteam_Users.UserOrgNo%TYPE;
SubUserOrgNo cteam_Users.UserOrgNo%TYPE;
UserOrgParentOrg cteam_OrgUnit.OrgParentNo%TYPE;
Unauthorized EXCEPTION;
ErrorMessage VARCHAR2(200);
BEGIN
SELECT UserOrgNo
INTO ApprOrgNo
FROM cteam_Users
WHERE UserOrgNo = :NEW.ApprUserNo;
SELECT UserOrgNo
INTO SubUserOrgNo
FROM cteam_Users
WHERE UserOrgNo = :NEW.SubmitUserNo;
SELECT DECODE OrgParentNo (UserOrgParentNo,'Null',Raise Unauthorized )
INTO UserOrgParentNo
FROM cteam_OrgUnit;
WHERE UserOrgParentNo = :NEW.OrgParentNo;
EXCEPTION
WHEN Unauthorized THEN
ErrorMessage := 'Unauthorised to update ' ;
END;
The trigger is fine up until the SELECT DECODE section.
FROM cteam_OrgUnit; - the semicolon shouldn't be there.
Your DECODE is formatted incorrectly. It might be that you wanted to write:
DECODE(OrgParentNo
UserOrgParentNo, 'Null',
Raise Unauthorized)
but you can't have an executable statement such as RAISE UNAUTHORIZED in a DECODE, which only deals with values. I suggest you rewrite your code as
CREATE OR REPLACE TRIGGER cteam_Trigger1
BEFORE INSERT OR UPDATE OF ApprUserNo ON cteam_ExpenseReport
FOR EACH ROW
DECLARE
vUserOrgParentNo cteam_OrgUnit.OrgParentNo%TYPE;
BEGIN
SELECT ou.OrgParentNo
INTO vUserOrgParentNo
FROM cteam_OrgUnit ou
WHERE ou.OrgParentNo = :NEW.OrgParentNo;
IF vUserOrgParentNo <> :NEW.ApprUserNo THEN
RAISE_APPLICATION_ERROR(-20000, 'Unauthorised to update');
END IF;
END;
I removed the SELECT statements where data was being fetched and never used; likewise, I removed the variables associated with those SELECTs. I replaced the DECODE with a CASE expression because I find a CASE expression is easier to read. I suggest that you prefix variables with an extra character, such as the v I added to vUserOrgParent, to prevent variable names from conflicting with column names in your tables. This is a potential source of problems which is easier to fix this way than any other. I also took some guesses as to the correct column names in your tables - if they're wrong feel free to fix them up.
Also - triggers cannot return error messages. The only way they can "communicate" with other code is by raising exceptions. I added a call to RAISE_APPLICATION_ERROR so the trigger can raise a known exception number.
I have these two tables
Project (projID,TotArticles)
Article (prodID,ArticleID)
How can I create a trigger to update by 1 the total amount of article every time someone published an article on it?
CREATE TRIGGER Art_Up
AFTER INSERT ON Article
FOR EACH ROW
UPDATE Project
SET TotArticle = TotArticle + 1
WHERE paperID = NEW.PaperID;
However, it gives me this error PLS-00103: Encountered the symbol ";"
You messed some names, once you write projID, once prodID, and in your trigger it is paperID. Also trigger has no begin ... end;. And you did not handle adding articles where projID does not exist in table project. You could check it at first or use rowcount after update and if it is 0 then use insert. More simple is to use merge.
create or replace trigger art_up after insert on article for each row
begin
merge into project
using (select :new.projid projid from dual) src
on (project.projid = src.projid)
when matched then update set totarticles = totarticles + 1
when not matched then insert (projID, TotArticles) values (:new.projid, 1);
end;
It works, I tested some basic inserts, but it is not recommended at all, because:
it's a bad idea to keep logic in triggers,
triggers can be droppped, disabled and then this information may be misleading, false,
we are slowing insert operations,
this trigger does not handle delete where you should decrement total number of articles.
Instead of trigger use simple view:
create or replace view vw_project as select projID, count(1) total from article group by projid;
I have created view in Oracle 12c using the following code:
CREATE VIEW ConcertView AS
SELECT a.ConcertNo, a.Concert_Name, a.Price, a.Duration, a.City, b.EventDate, b.Even t_Name
FROM Concert a,Events b
WHERE a.ConcertNo = b.ConcertNo
AND a.ConcertNo != 'CN002'
The view creates without any errors. I then create a trigger on the view using the following code:
CREATE OR REPLACE TRIGGER check_month
INSTEAD OF DELETE OR INSERT OR UPDATE ON ConcertView
DECLARE
ConcertDate date;
BEGIN
IF (to_char(EventDate, 'DD-MM-YY') = 'JUL') THEN
raise_application_error(-20000, 'Concerts cannot be run during JULY');
END IF;
END;
Trigger created.
The trigger creates without any errors.
I am trying to ensure that concerts cannot be run during July.
However the trigger does not take any action. Could anybody please let me know what I am doing wrong, or explain how to test a trigger?
Replace this sentence:
IF (to_char(EventDate, 'DD-MM-YY') = 'JUL')
For this:
IF to_char(EventDate, 'MON') = 'JUL'
In the first sentence you are comparing the date in the format DD-MM-YY with the name of the month. In the second, you're going to compare the name of the month.
You can check the doc here:
Oracle Doc.
Where is the bug? Compilation ends with errors and I have no idea where I'm going wrong.
create or replace
PROCEDURE make_payoff(user_id_argument number)
is
begin
payoff_amount:= 0;
CURSOR Clicks IS
SELECT c.cpc FROM click as c JOIN widget w ON w.id = c.widget_id JOIN website web ON web.id = w.website_id WHERE web.user_id = user_id_argument AND c.payoff_id IS NULL;
BEGIN
FOR Click IN Clicks
LOOP
payoff_amount:= payoff_amount + Click.cpc;
END LOOP;
INSERT INTO payoff (user_id, amount) VALUES (user_id_argument, payoff_amount);
COMMIT;
end;
I'm getting:
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00905: object S10306.MAKE_PAYOFF is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
EDIT:
I've fixed Cursor name but error is the same
This is the error you get when you try to use the procedure. Not the error you get when you compile it. You need to find the error you get when you compile the procedure, probably using show errors and attempt to solve that problem.
Your problem is that for click in click should be for click in clicks... Not the extra s, so you are looping through the cursor.
Additionally, in your cursor you've written FROM click as c, which is not valid in Oracle. This should be FROM click c
And two BEGINs... remove the first one.
Alex Poole has noted that you've also not declared the type of the variable payoff_amount. You should declare this as a number:
payoff_amount number := 0;
However, there is no need to do this, no need to loop, no need to use a procedure at all. This is possible with a single SQL statement:
insert into payoff (user_id, amount)
select 'user_id_argument', sum(c.cpc)
from click c
join widget w
on w.id = c.widget_id
join website web
on web.id = w.website_id
where web.user_id = user_id_argument
and c.payoff_id IS NULL;
You missed s.
FOR Click IN Clicks
LOOP
payoff_amount:= payoff_amount + Click.cpc;
END LOOP;
Anyway, don't name variables and cursors so close to database fields. Add some prefix, for example, to differentiate easily.
I created a procedure for my user under the user sys. When starting the procedure, I received the same errors as yours. The procedure was valid. Recompiling the object under different users did not help solve the problem. I drop the procedure and created it as my user. Problem solved.