Updating another table in an Oracle Trigger - sql

I've prepared the following trigger create statement yet it does not compile.
CREATE OR REPLACE TRIGGER UpdIssueTypScrSchmSeq
AFTER INSERT
ON ISSUETYPESCREENSCHEME
FOR EACH ROW
DECLARE
maxID NUMBER(18,0);
BEGIN
select max(ID) into maxID from ISSUETYPESCREENSCHEME;
UPDATE SEQUENCE_VALUE_ITEM
SET SEQ_ID = maxID + 1
WHERE SEQ_NAME = 'IssueTypeScreenSchemeEntity';
END;
I keep getting error messsages saying "maxID must be declared".
Anybody know what is wrong?
Propbably does not make a difference but I am working with SQL Developer on Windows.

Related

Select from table that does not exist

I have a question regarding ORACLE, I wrote a PLSQL CODE that checks if a table exists, if it exists then I select something from this table..pseudocode is like:
if (table exists)
Select from table where....
the problem is that I always get an error if the table does not exist, even if the if condition is never met and the select statement is never executed.
I think it is because my code is checked at compile time: "select from.." and then it prints an error if the table does not exist. How can I solve such an issue?.. here is how my code looks like (I used generic names):
DECLARE
v_table_exists NUMBER;
BEGIN
SELECT NVL(MAX(1), 0)
INTO v_table_exists
FROM ALL_TABLES
WHERE TABLE_NAME = 'TABLE_TEST';
IF v_table_exists = 1 THEN
INSERT INTO MY_TABLE(COLUMN1, COLUMN2, COLUMN3, COLUMN4)
SELECT 1234,
5678,
T.COLUMN_TEST1,
T.COLUMN_TEST2
FROM TABLE_TEST T
WHERE T.FLAG = 1;
END IF;
END;
The issue is exactly in the fact that your procedure con not be compiled as it refers to a non existing object; you may need some dynamic SQL for this; for example:
create or replace procedure checkTable is
vCheckExists number;
vNum number;
begin
-- check if the table exists
select count(1)
into vCheckExists
from user_tables
where table_name = 'NON_EXISTING_TABLE';
--
if vCheckExists = 1 then
-- query the table with dynamic SQL
execute immediate 'select count(1) from NON_EXISTING_TABLE'
into vNum;
else
vNum := -1;
end if;
dbms_output.put_line(vNum);
end;
The procedure compiles even if the table does not exist; if you call it now, you get:
SQL> select count(1) from NON_EXISTING_TABLE;
select count(1) from NON_EXISTING_TABLE
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> exec checkTable;
-1
PL/SQL procedure successfully completed.
Then, if you create the table and call the procedure again:
SQL> create table NON_EXISTING_TABLE(a) as select 1 from dual;
Table created.
SQL> exec checkTable;
1
PL/SQL procedure successfully completed.
The same way I showed a SELECT, you can do an UPDATE or whatever SQL query you need; if you do something different from a SELECT, the INTO clause has to be removed.
For example, say you need to insert into a different table, the above code should be edited this way:
if vCheckExists = 1 then
execute immediate 'insert into target(a, b, c) select a, 1, 100 from NON_EXISTING_TABLE';
end if;
Everything will need to be done in Dynamic SQL (DBMS_SQL) or EXECUTE_IMMEDIATE otherwise your code will never compile (or package will be invalided) if table does not exists.
DBMS_SQL Example
EXECUTE_IMMEDIATE Example
According to this article, in Oracle Database Server static SQL is indeed checked at compile time to ensure referenced objects exist.
So I advise you to use dynamic SQL instead of static SQL, through a varchar for example.

Oracle Trigger - update table B based on a condition of table A

I'm attempting to create an Oracle trigger which sets the values of a column on table B based on a select statement run within the trigger.
I want to be able to set the values of the 'is_active' column in table B to 'N' based on the select statement after an insert on table A has been executed.
My query is as follows:
CREATE OR REPLACE TRIGGER INACTIVE_STATE
AFTER INSERT ON
COMMENTS
FOR EACH ROW
DECLARE
inactive_id number;
BEGIN
SELECT distinct b.id
into inactive_id
from comments a,
modules b
where a.module_name=b.name
and a.type_id='FUNCTIONAL'
and a.module_id=b.id;
update modules
set is_active='N'
where ID=:inactive_id
END INACTIVE_STATE;
/
When I try and complpile this trigger, I get the following errors:
Error(15,1): PL/SQL: SQL Statement ignored
Error(17,10): PLS-00049: bad bind variable 'INACTIVE_ID'
Error(17,15): PL/SQL: ORA-00933: SQL command not properly ended
Error(19,1): PLS-00103: Encountered the symbol "/" 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 <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
It seems it doesn't like the update statement, or the bind variable isn't being parsed within this process.
If I seperate these statements into 2 commands (using var to handle the bind variable :inactive_id) it works as expected.
VAR INACTIVE_ID number
begin
select distinct b.id into :INACTIVE_ID
from comments a,
modules b
where a.module_name=b.name
and a.type_id='FUNCTIONAL'
and a.module_id=b.id;
end;
/
PL/SQL procedure successfully completed.
SQL>
SQL> update modules
set is_active='N'
where ID=:INACTIVE_ID
/
1 row updated.
Any ideas what I might be overlooking?
As Tony Andrews pointed out in the comments of the original post, I was incorrectly using a colon before the "inactive_id" variable in the where clause.
The correct code should have been:
CREATE OR REPLACE TRIGGER INACTIVE_STATE
AFTER INSERT ON
COMMENTS
DECLARE
inactive_id number;
BEGIN
SELECT distinct b.id
into inactive_id
from comments a,
modules b
where a.module_name=b.name
and a.type_id='FUNCTIONAL'
and a.module_id=b.id;
update modules
set is_active='N'
where ID=inactive_id
END INACTIVE_STATE;
/
Try using
PRAGMA AUTONOMOUS_TRANSACTION;
before begin

ORA-04071: missing BEFORE, AFTER or INSTEAD OF keyword Error

CREATE TRIGGER TRG_LOADMONEY
ON KIOSK
AFTER INSERT
AS
DECLARE #LOADEDCARDID INT
DECLARE #LOADEDAMOUNT INT
SELECT #LOADEDCARDID = LOADEDCARDID, #LOADEDAMOUNT = LOADEDAMOUNT FROM INSERTED
UPGRADE CARD SET CHARGE = CHARGE + #LOADEDAMOUNT
WHERE CARDID = #LOADEDCARDID
I run this code, but i am having an error which is "ORA-04071: missing BEFORE, AFTER or INSTEAD OF keyword". I have AFTER statement, i dont understand what is the problem.
You have used syntax is for sql server.
Try this:
CREATE OR REPLACE TRIGGER TRG_LOADMONEY
AFTER INSERT
ON KIOSK FOR EACH ROW
/*
These variables are not required because Oracle triggers can reference the table's
columns directly using the :OLD and :NEW prefixes.
DECLARE
LOADEDCARDID PLS_INTEGER;
LOADEDAMOUNT PLS_INTEGER;
*/
BEGIN
UPDATE CARD
SET CHARGE = CHARGE + :NEW.LOADEDAMOUNT
WHERE CARDID = :NEW.LOADEDCARDID;
END;

need to write a trigger

I want to write a trigger for a table "TRANSACTION".When a new line is inserted, I want to trigger to update the field "TRANSACTIONID" to the maximum + 1 of all the previous records.
I on't know much about SQL. Can someone help me?
many thanks
This is a really bad idea for a multi-user environment, as it will serialise inserts into the table. The usual approach is to use an Oracle sequence:
create sequence transaction_seq;
create trigger transaction_bir before insert on transaction
for each row
begin
:new.id := transaction_seq.nextval;
end;
To write a trigger based solution that actually got the max current value plus 1, you would need to write a complex 3-trigger solution to avoid the "mutating table" issue. Or you could create a simpler solution using another table to hold the current maximum value like this:
create table transaction_max (current_max_id number);
insert into transaction_max values (0);
create trigger transaction_bir before insert on transaction
for each row
declare
l_current_max_id number;
begin
update transaction_max set current_max_id = current_max_id + 1
returning current_max_id into l_current_max_id;
:new.id := l_current_max_id;
end;
This will avoid the mutating table issue and will serialize (slow down) inserts, so I don't see any advantage of this over using a sequence.
CREATE TRIGGER trigger1 on TransactionTable
INSTEAD OF INSERT
AS
BEGIN
DECLARE #MaxTranId INT
SELECT
#MaxTranId = MAX(TransactionId)
FROM
TransactionTable
INSERT INTO TransactionTable
SELECT
#MaxTranId + 1 ,
RestOfYourInsertedColumnsHere ,
FROM
inserted
END
GO

Error creating trigger

This is a simple trigger I'm trying to create:
CREATE TRIGGER add_item_id BEFORE INSERT ON products
FOR EACH ROW
BEGIN
DECLARE max_id INTEGER;
SELECT MAX(item_id) INTO #max_id FROM products;
SET NEW.item_id = #max_id + 1;
END;
I tried it both on phpMyAdmin SQL window and mysql prompt and get the same error as below:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 4
delimiter //
CREATE TRIGGER add_item_id BEFORE INSERT ON products
FOR EACH ROW
BEGIN
DECLARE max_id int;
SELECT MAX(item_id) INTO max_id FROM products;
SET NEW.item_id = max_id + 1;
END//
delimiter ;
Some notes:
If you declare (local variable) max_id, use it. #max_id is a GLOBAL variable. Any #variable can be used without declaring it, but it stays with the session as long as the session lives.
Your code is fine, you are just missing the delimiter changes. Without delimiter //, MySQL sees the CREATE TRIGGER statement ending at ..FROM PRODUCTS;, which makes it invalid
You could also do:
CREATE TRIGGER add_item_id
BEFORE INSERT
ON products
FOR EACH ROW
BEGIN
SET NEW.item_id = 1 + ( SELECT MAX(item_id)
FROM products
) ;
END;
Note: you can declare auto_incremented fields in almost all RDBMS.