Trigger created with compilation errors. ORA-:missing SELECT keyword - oracle

I am trying to create a trigger that fires after an insert/update and checks for null values in couple of columns. In case any one of them is NULL, it queries other tables and updates the current table
CREATE OR REPLACE TRIGGER sample_trigger
AFTER INSERT OR UPDATE
ON test_table
FOR EACH ROW
BEGIN
IF :NEW.ID IS NULL OR :NEW.CODE IS NULL
THEN
UPDATE (:NEW.ID,:NEW.CODE) = (SELECT T1.ID,
T2.CODE
FROM TABLE_1 T1
JOIN TABLE_2 T2 ON T1.ID=T2.ID
WHERE ID=:NEW.TEST_ID);
END IF;
END;
/
Warning: Trigger created with compilation errors.
ERROR: PL/SQL: ORA-00928: missing SELECT keyword

You don't UPDATE the :new pseudo-record. Just assign values to it
SELECT t1.id, t2.code
INTO :new.id, :new.code
FROM table1 t1
join table2 t2 on t1.id = t2.id
WHERE id = :new.test_id
A couple additional notes
Your WHERE clause will generate an ambiguous reference error. Since both t1 and t2 have an ID column, you'd need to specify which table's column you are comparing against.
If test_table is the same as either table_1 or table_2, that's going to produce a mutating table exception.
Your trigger should be a BEFORE INSERT since it's modifying data not an AFTER INSERT trigger.

Triggers have to follow syntax as any other program unit; UPDATE you wrote is invalid (obviously), but - you don't need it. Here's what you might have done:
declare two variables which will hold ID and CODE values
set TEST_TABLES's columns values to those variables
CREATE OR REPLACE TRIGGER sample_trigger
AFTER INSERT OR UPDATE
ON test_table
FOR EACH ROW
DECLARE
l_id test_table.id%type;
l_code test_table.code%type;
BEGIN
IF :NEW.ID IS NULL OR :NEW.CODE IS NULL
THEN
SELECT t1.id, t2.code
INTO l_id , l_code
FROM table_1 t1 JOIN table_2 t2 ON t1.id = t2.id
WHERE id = :new.test_id;
:new.id := l_id;
:new.code := l_code;
END IF;
END;
/

Related

Creating AFTER INSERT TRIGGER on Oracle table

I don’t know how to create AFTER INSERT TRIGGER with the condition Table_1.Table_2_ID = Table_2.ID .
CREATE OR REPLACE TRIGGER Table_2_TRG
AFTER INSERT
ON Table_1
FOR EACH ROW
BEGIN
UPDATE Table_2
SET Col1 = '1'
FROM (SELECT Table_2_ID FROM Table_1)
WHERE Table_1.Table_2_ID = Table_2.ID;
END;
It is needed to change record’s value in the Table_2 AFTER INSERT a record in the Table_1 with the similar ID (Table_2_ID in the Table_1 and ID in the Table_2 are identical).
Col1 in the Table_2 has type VARCHAR2.
I have this code, but after running statement there is an error:
“2/5 PL/SQL: SQL Statement ignored
4/5 PL/SQL: ORA-00933: SQL command not properly ended”
If I got it right, you need such a WHERE clause:
CREATE OR REPLACE TRIGGER Table_2_TRG
AFTER INSERT
ON Table_1
FOR EACH ROW
BEGIN
UPDATE Table_2 b
SET b.Col1 = '1'
WHERE b.id = :new.table_2_id;
END;
this will work:
CREATE OR REPLACE TRIGGER Table_2_TRG
AFTER INSERT
ON Table_1
FOR EACH ROW
BEGIN
UPDATE Table_2
SET Col1 = '1'
where id=:new.id;
END;

How to get name of the employee while triggering his salary?

create or replace trigger trg_t3 after
insert OR update or delete of salary on t2
for each row
begin
if
to_char(systimestamp,'hh24') not between 9 and 17
then
insert into t3 values (:new.salary, :old.salary, sysdate);
else
DBMS_OUTPUT.put_line ('update is not possible between 9:00 and 17:00');
end if;
end;
/
this will insert old salary ,new salary and the time on table t3 based on the conditions mentioned in trigger on table t2. But i need the name of the employee whose salary is updated or delete.
if i am updating a salary on t2 i need to insert the name of the specific employee whose salary i have modified into t3. But current method will only insert old salary, new salary and time
here is the code for creating the tables
create table t2 ( name varchar(20), salary varchar2(20));
create table t3 (salary_new varchar2(50), salary_old varchar2(20), log_date date);
insert all
into t2 values('hari',2000)
into t2 values('sam',40000)
into t2 values('ravi',60000)
into t2 values('manoj',8000)
into t2 values('pratheep',10000)
into t2 values('john',3000)
into t2 values('joe',50000)
into t2 values('scott',70000)
select * from dual;
Your trigger is marked as after insert or update or delete. You have to handle all three situations otherwise it will not work correctly, because when inserting we have no :old values and when deleting there are no :new.
So if you use :new.name then delete will put null value. If you use :old.name then insert will not work correctly. Use variable or do it like here:
create or replace trigger trg_t3 after
insert or update or delete of salary on t2 for each row
begin
if to_char(systimestamp,'hh24') between 9 and 17 then
dbms_output.put_line ('update is not possible between 9:00 and 17:00');
else
if deleting then
insert into t3 (salary_new, salary_old, name, log_date)
values (null, :old.salary, :old.name, sysdate);
elsif inserting then
insert into t3 (salary_new, salary_old, name, log_date)
values (:new.salary, null, :new.name, sysdate);
elsif updating then
insert into t3 (salary_new, salary_old, name, log_date)
values (:new.salary, :old.salary, :new.name, sysdate);
end if;
end if;
end;
Do an insert select
insert into t3
select emp.name, :new.salary, :old.salary, sysdate
from emp where emp.id = :old.id;
first you need a field to insert the name into so create t3 as
create table t3 (salary_new varchar2(50), salary_old varchar2(20), log_date date, name varchar(20));
then in your trigger simply use
insert into t3 values (:new.salary, :old.salary, sysdate, :new.name);
you could use either :new.name or :old.name as it is not changing so would be the same value.

Create a table in Oracle SQL If table does not exist using select and join

The question is very common, but I am facing one single issue in there for which I am not able to find the answer.
What I have to do is, create a table if the table does not exist.
But while creating the table, I need to create it from the select query(which is result of JOIN of two tables).
This is for "ORACLE SQL DEVELOPER" / "PL/SQL".
The query I am using is:
DECLARE
count_matching_tbl BINARY_INTEGER := 0;
BEGIN
SELECT COUNT(*)
INTO count_matching_tbl
FROM dba_tables
WHERE LOWER(table_name) = 'testtable';
IF(count_matching_tbl = 0)
THEN
EXECUTE IMMEDIATE ( ' CREATE TABLE testtable AS (SELECT A.*, B.* from tab1 A JOIN tab2 B ON A.id = B.RID WHERE 1=2)');
END IF;
END;
If tab1 and tab2 table has same name column then ambiguity occure while creating table and inserting record so instead of * replace table column which is add in testtable like
CREATE TABLE testtable AS (SELECT A.cola1, B.colb1 from tab1 A JOIN tab2 B ON A.id = B.RID WHERE 1=2
ask your dba to give "select on dba_tables " to your schema .
Since you are using a pl/sql procedure , you need to have permissions granted directly to you rather than through a role.
The issue was because of the static SQL data.
The table was created dynamically, but the rest of the statements were trying to access the static data.
To solve this, I have created two anonymous blocks, the first one having the create table statement, commit it and end the block.
The next anonymous block will have the rest of the statements to be executed after the IF clause.
This solved my problem.
DECLARE
count_matching_tbl BINARY_INTEGER := 0;
BEGIN
SELECT COUNT(*)
INTO count_matching_tbl
FROM dba_tables
WHERE LOWER(table_name) = 'testtable';
IF(count_matching_tbl = 0)
THEN
EXECUTE IMMEDIATE ( ' CREATE TABLE testtable AS (SELECT A.*, B.* from tab1 A JOIN tab2 B ON A.id = B.RID WHERE 1=2)');
COMMIT;
END IF;
END;
/
BEGIN
-- Rest of the database execution statements
COMMIT;
END;
/

picking 1 column from 2 tables and comparing them

In my Oracle database there are two tables which are TEMP_HR and PAY_SLIP_APR_16. Both of them have a common column named EMP_ID. TEMP_HR has over 10,000 records and PAY_SLIP_APR_16 has around 6,000 records. I want to know how many EMP_ID of PAY_SLIP_APR_16 is matched with TEMP_HR. If any ID doesn't match then print it. And here is my simple approach but I think its a very bad approach. So any faster method?
DECLARE
INPUT_EMP_NO VARCHAR2(13 BYTE);
INPUT_EMP_ID VARCHAR2(13 BYTE);
ROW_COUNT_1 NUMBER(6,0);
ROW_COUNT_2 NUMBER(6,0);
MATCHED_ID NUMBER;
UNMATCHED_ID NUMBER;
BEGIN
ROW_COUNT_1:=0;
ROW_COUNT_2:=0;
MATCHED_ID:=0;
UNMATCHED_ID:=0;
SELECT COUNT(*) INTO ROW_COUNT_1 FROM PAY_SLIP_APR_16;
SELECT COUNT(*) INTO ROW_COUNT_2 FROM TEMP_HR;
FOR A IN 1..ROW_COUNT_1 LOOP
BEGIN
SELECT EMP_ID INTO INPUT_EMP_ID FROM (SELECT EMP_ID, ROWNUM AS RN FROM PAY_SLIP_APR_16) WHERE RN=A;
FOR B IN 1..ROW_COUNT_2 LOOP
SELECT EMP_NO INTO INPUT_EMP_NO FROM (SELECT EMP_NO, ROWNUM AS RON FROM TEMP_HR) WHERE RON=B;
IF(INPUT_EMP_ID=INPUT_EMP_NO)THEN
MATCHED_ID:=MATCHED_ID+1;
EXIT;
ELSE
CONTINUE;
END IF;
END LOOP;
UNMATCHED_ID:=UNMATCHED_ID+1;
DBMS_OUTPUT.PUT_LINE(INPUT_EMP_ID);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(INPUT_EMP_ID||' -> '||SQLERRM);
END;
END LOOP;
DBMS_OUTPUT.PUT_LINE('MATCHED -> '||MATCHED_ID);
DBMS_OUTPUT.PUT_LINE('UNMATCHED -> '||UNMATCHED_ID);
END;
Use an outer join filtering for missed joins:
select p.*
from PAY_SLIP_APR_16 p
left join TEMP_HR t on t.EMP_ID = p.EMP_ID
where t.EMP_ID is null
An index on TEMP_HR(EMP_ID) will make this query fly.
You should use SQL sets!
To check which EMP_ID isn't in TEMP_HR you may try this:
select EMP_ID FROM PAY_SLIP_APR_16
where EMP_ID not in (select EMP_NO from TEMP_HR);
Then the other way around:
select EMP_NO FROM TEMP_HR
where EMP_NO not in (select EMP_ID from PAY_SLIP_APR_16);

create trigger by checking the value of a field being inserted in oralce

I need to create a before insert trigger on TABLE1 such that it inserts COL2 and COL3 of the new row being inserted in TABLE1 into TABLE2 only when TABLE1.FIELD1 = 'XYZ'. How do I do this so that trigger gets fired only when the condition is met?
CREATE OR REPLACE TRIGGER my_trigger
before insert
ON table_1
FOR EACH ROW
BEGIN
IF :NEW.FIELD1 = 'XYZ'
then
INSERT INTO table_2 (col1, col2) VALUES (:NEW.col1, :NEW.col2);
END IF;
END;
/
or how a_horse_with_no_name noted, your can use the the WHEN clause
CREATE OR REPLACE TRIGGER my_trigger
before insert
ON table_1
FOR EACH ROW
WHEN (NEW.FIELD1 = 'XYZ')
BEGIN
INSERT INTO table_2 (col1, col2) VALUES (:NEW.col1, :NEW.col2);
END;
/

Resources