Error on executing trigger - sql

CREATE OR REPLACE TRIGGER PROCESS_POPULATE_INSTANCE
AFTER INSERT OR UPDATE ON PROCESS_INSTANCE
FOR EACH ROW
DECLARE
InstanceExists NUMBER;
BEGIN
SELECT COUNT(*)
INTO InstanceExists
FROM TEST_PROCESSDATA
WHERE TEST_PROCESSDATA.PROCESS_INSTANCE_ID = :NEW.INSTANCE_ID ;
IF ( InstanceExists > 0 ) THEN
UPDATE TEST_PROCESSDATA SET PROCESS_STATUS =:NEW.STATUS WHERE PROCESS_INSTANCE_ID = NEW.INSTANCE_ID;
ELSIF
INSERT INTO TEST_PROCESSDATA (PROCESS_INSTANCE_ID,PROCESS_STATUS, STARTED_TIME) VALUES (:NEW.INSTANCE_ID,:NEW.STATUS,:NEW.START_TIME);
END IF;
END PROCESS_POPULATE_APPDATA;
On executing the above trigger, i get the below error:
Error(12,2): PLS-00103: Encountered the symbol "INSERT" when expecting one of the following: ( - + case mod new not null continue avg count current exists max min prior sql
stddev sum variance execute forall merge time timestamp interval
date
pipe
Error(13,2): PLS-00103: Encountered the symbol "END"

In addition to what Ravindra bagale has already noted I would add the following:
First. In the statement
UPDATE TEST_PROCESSDATA SET PROCESS_STATUS =:NEW.STATUS
WHERE PROCESS_INSTANCE_ID = NEW.INSTANCE_ID;
: colon is missing in front of NEW.INSTANCE_ID
And second. You might consider using of merge statement instead of IF .. THEN .. ELSE.. END IF construct and additional select statement. For example.
create or replace trigger process_populate_instance
after insert or update on process_instance
for each row
begin
merge into test_processdata
using dual
on (process_instance_id = :new.instance_id)
when matched
then update
set process_status =:new.status
when not matched
then insert (process_instance_id,process_status, started_time)
values (:new.instance_id,:new.status,:new.start_time);
end;

use ELSE instead of ELSIF
here u used elseif,but not used else, u can't use elseif without else
when there are more than two way then u can use elsif.
IF ( InstanceExists > 0 ) THEN
UPDATE TEST_PROCESSDATA SET PROCESS_STATUS =:NEW.STATUS WHERE PROCESS_INSTANCE_ID = NEW.INSTANCE_ID;
ELSE
INSERT INTO TEST_PROCESSDATA (PROCESS_INSTANCE_ID,PROCESS_STATUS, STARTED_TIME) VALUES (:NEW.INSTANCE_ID,:NEW.STATUS,:NEW.START_TIME);
END IF;
END PROC

Related

"If" in a trigger comparing two columns from 2 different tables- error

Im trying to create a trigger when updating table 'test' to make sure a value in a column is not greater than another one from a different table. But I get this error on Oracle Apex: ORA-24344: success with compilation error
'test' is a table and 'chestionar' is a second one, so I want to launch that error when I insert a value in 'punctaj' which is greater than the 'punctaj_max'. And the id of the both tables must be the same . What should I modify?
here is my code:
CREATE OR REPLACE trigger trg_a
BEFORE UPDATE on test
begin
if test.punctaj > chestionar.punctaj_max and test.id=chestionar.id then
raise_application_error(234,'error, the value is grater than maximum of that id');
end if;
end;
I think the logic you want is:
create or replace trigger trg_a
before update on test
for each row
declare
p_punctaj_max chestionar.punctaj_max%type;
begin
select punctaj_max into p_punctaj_max from chestionar c where c.id = :new.id;
if :new.punctaj > p_punctaj_max then
raise_application_error(234, 'error, the value is grater than maximum of that id');
end if;
end;
/
The idea is to recover the value of punctaj_max in table chestionar for the id of the row that is being updated in test (note that this implicitely assumes that there cannot be multiple matching rows in chestionar). We can then compare that to the value being updated, and raise the error if needed.
You have three (I think) issue in your code:
You should apply trigger at time of insert also.
you need to query the table chestionar and then compare the value.
the error number in raise_application_error should be negative and between -20999 and -20000.
So, I would rewrite your code as follows:
create or replace trigger trg_a
before update or insert on test
for each row
declare
lv_cnt number := 0;
begin
select count(1) into lv_cnt
from chestionar c
where c.id = :new.id
and :new.punctaj > c.punctaj_max;
if lv_cnt > 0 then
raise_application_error(-20234, 'error, the value is grater than maximum of that id');
end if;
end;
/

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;
/

foreach rows of my table and update my ROW_NUMBER column

I would like to create a script pl/sql where I can modify the value of my column ROW_NUMBER (the first time the value of ROW_NUMBER equal NULL).
This is the structure of my table 'A' :
CREATE TABLE A
(
"NAME" VARCHAR2(25 BYTE),
"NUM" NUMBER(10,0)
)
I would like to foreach all rows of table A and increment my Column 'NUM' by 1 if Column 'NAME' equal 'DEB'.
I would like to get the result like :
I created one pl/sql script :
DECLARE
INcrmt NUMBER(4):=1;
line WORK_ODI.TEST_SEQ%ROWTYPE;--before fetch it returns 0
CURSOR c_select IS
SELECT ROW_NUMBER,VALUE FROM WORK_ODI.TEST_SEQ;
BEGIN
OPEN c_select;
LOOP
FETCH c_select INTO line;
DBMS_OUTPUT.PUT_LINE(line.VALUE);
if line.VALUE like '%DEB%'
then
UPDATE WORK_ODI.TEST_SEQ SET ROW_NUMBER = INcrmt WHERE VALUE=line.VALUE;
INcrmt := INcrmt + 1;
end if;
if line.VALUE not like '%DEB%'
then
UPDATE WORK_ODI.TEST_SEQ SET ROW_NUMBER = INcrmt WHERE VALUE=line.VALUE;
end if;
EXIT WHEN c_select%NOTFOUND;
END LOOP;
CLOSE c_select;
COMMIT;
END;
DECLARE
INcrmt NUMBER(4):=1;
line WORK_ODI.TEST_SEQ%ROWTYPE;--before fetch it returns 0
CURSOR c_select IS
SELECT ROW_NUMBER,VALUE FROM WORK_ODI.TEST_SEQ;
BEGIN
OPEN c_select;
LOOP
FETCH c_select INTO line;
DBMS_OUTPUT.PUT_LINE(line.VALUE);
if line.VALUE like '%DEB%'
then
UPDATE WORK_ODI.TEST_SEQ SET ROW_NUMBER = INcrmt WHERE VALUE=line.VALUE;
INcrmt := INcrmt + 1;
end if;
if line.VALUE not like '%DEB%'
then
UPDATE WORK_ODI.TEST_SEQ SET ROW_NUMBER = INcrmt WHERE VALUE=line.VALUE;
end if;
EXIT WHEN c_select%NOTFOUND;
END LOOP;
CLOSE c_select;
COMMIT;
END;
but this is not work well , please take a look at what it gives me as result :
please anybody can help me
First, you should have an Aid column of some sort. In Oracle 12+, you can use an identity. In earlier versions, you can use a sequence. This provides an ordering for the rows in the table, based on insert order.
Second, you can do what you want on output:
select a.*,
sum(case when a.name like 'DEB%' then 1 else 0 end) over (order by aid) as row_number
from a;
If you really need to keep the values in the table, then you can use a merge statement to assign values to existing rows (the aid column is very handy for this). You will need a trigger afterwards to maintain it.
My suggestion is to do the calculation on the data, rather than storing the value in the data. Maintaining the values with updates and deletes seems like a real pain.

Trigger in Oracle giving error

This is my sql code:
CREATE OR REPLACE TRIGGER PLACE_NO_TRIGGER
BEFORE INSERT or UPDATE ON UHA_LEASE
FOR EACH ROW BEGIN
INSERT INTO UHA_TEMPVAL SELECT PLACE_NO FROM UHA_RESHALL;
INSERT INTO UHA_TEMPVAL SELECT PLACE_NO FROM UHA_GENERAL;
IF(:NEW.PLACE_NO NOT IN UHA_TEMPVAL.TEMP_VALUE AND :NEW.PLACE_NO IS NOT NULL) THEN
RAISE_APPLICATION_ERROR(-10001, 'PLACE_NO MUST BE IN UHA_RESHALL OR IN UHA_GENERAL OR NULL');
END IF;
DELETE FROM UHA_TEMPVAL;
END;
This is giving these errors:
Error(4,27): PLS-00103: Encountered the symbol "UHA_TEMPVAL" when expecting one of the following: ( The symbol "(" was substituted for "UHA_TEMPVAL" to continue.
Error(4,69): PLS-00103: Encountered the symbol "THEN" when expecting one of the following: ) , and or as The symbol ")" was substituted for "THEN" to continue.
Can someone help me understand why these errors are occurring? It's especially odd because row 4 ends at column 60.
Thanks!
It looks like you're trying to enforce referential integrity from a child table to either of two parent tables. You don't really need to insert and delete from a temporary table; you can count how many rows match in either table:
CREATE OR REPLACE TRIGGER PLACE_NO_TRIGGER
BEFORE INSERT or UPDATE ON UHA_LEASE
FOR EACH ROW
DECLARE
CNT NUMBER;
BEGIN
SELECT COUNT(*)
INTO CNT
FROM (
SELECT PLACE_NO FROM UHA_RESHALL
WHERE PLACE_NO = :NEW.PLACE_NO
UNION ALL
SELECT PLACE_NO FROM UHA_GENERAL
WHERE PLACE_NO = :NEW.PLACE_NO
);
IF :NEW.PLACE_NO IS NOT NULL AND CNT = 0 THEN
RAISE_APPLICATION_ERROR(-10001,
'PLACE_NO MUST BE IN UHA_RESHALL OR IN UHA_GENERAL OR NULL');
END IF;
END;
/
You could choose to only run the query if the :NEW.PLACE_NO is not null but it probably won't make much difference if the columns are indexed.

UPDATE table with PL/SQL trigger?

I have this trigger, and I am getting an arror message when I run it; "bad bind variable".
I can't seem to see where the problem lies. Any help would be appreciated.
create or replace TRIGGER trg_placed AFTER UPDATE
OF STATUS_ID ON STATUS
FOR EACH ROW
BEGIN
IF :new.STATUS_ID = 7
THEN
UPDATE STUDENT
SET PLACED_Y_N = 'Y'
WHERE RECORD_NUMBER = :NEW.record_number;
END IF;
END;
try like this:
create or replace TRIGGER trg_placed AFTER UPDATE
OF STATUS_ID ON STATUS
REFERENCING OLD AS o NEW AS n
FOR EACH ROW
BEGIN
IF n.STATUS_ID = 7
THEN
UPDATE STUDENT
SET PLACED_Y_N = 'Y'
WHERE RECORD_NUMBER = n.record_number;
END IF;
END;
If you use lowercase for Oracle objects, you'll have to surround object names with quotes (") and match the case exactly to get it to work.
like this
create or replace TRIGGER trg_placed AFTER UPDATE
OF STATUS_ID ON STATUS
FOR EACH ROW
BEGIN
IF :new.STATUS_ID = 7
THEN
UPDATE STUDENT
SET PLACED_Y_N = 'Y'
WHERE RECORD_NUMBER = :NEW."record_number"; --quotes (") required for column name.
END IF;
END;