DROP TRIGGER EPI_BOREHOLE_INI;
CREATE OR REPLACE TRIGGER EPI_BOREHOLE_INI
INSTEAD of Insert ON EPI_BOREHOLE for each row
DECLARE
V_ID number(10);
V_USER varchar2(100);
BEGIN
if (:new.UBHI is null or :new.NAME is null or) then
Raise_Application_Error(-20101, 'Insert failed. The key values of BOREHOLE(UBHI, NAME) cannot be null');
end if;
begin
select BOREHOLE_ID.nextval into V_ID from dual;
SELECT USER INTO V_USER FROM DUAL;
INSERT INTO EPI_BOREHOLE (ID, UBHI, NAME, INSERT_DATE ,INSERT_NAME, UPDATE_DATE,UPDATE_NAME) VALUES (V_ID,:NEW.UBHI, :NEW.NAME, SYSDATE, V_USER, SYSDATE, V_USER);
end;
END;
I see little error in your code: Please see below:
if (:new.UBHI is null or :new.NAME is null or) then <-- An additional OR written.
remove it and try or put one more condition.
I dont see any issue with the code.
Try doing
SET DEFINE OFF
Related
This is a question about Oracle PL/SQL.
I have a procedure in which the exact WHERE clause is not known until the run time:
DECLARE
CURSOR my_cursor is
SELECT ...
FROM ...
WHERE terms in (
(SELECT future_term2 FROM term_table), -- whether this element should be included is conditional
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
);
BEGIN
(the processing)
END;
/
What the (SELECT ... FROM term_table) query returns is a 4-character string.
For a solution to this, I am thinking of using a parameterized cursor:
DECLARE
target_terms SOME_DATATYPE;
CURSOR my_cursor (pi_terms IN SOME_DATATYPE) IS
SELECT ...
FROM ...
WHERE terms in my_cursor.pi_terms;
BEGIN
target_terms := CASE term_digit
WHEN '2' THEN (
(SELECT future_term2 FROM term_table),
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
) ELSE (
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
)
END;
FOR my_record IN my_cursor (target_terms) LOOP
(the processing)
END LOOP;
END;
/
The problem is what the datatype for SOME_DATATYPE should be is not known to me, nor is it known whether Oracle supports such a cursor parameter at all. If supported, is the way shown above to fabricate the value for target_terms correct? If not, how?
Hope someone who know can advise. And thanks a lot for the help.
You can certainly pass a parameter to a cursor, just like you can to a function - but only IN parameters. However, PL/SQL is a strongly typed language, so the datatype must be specified at the time of compilation.
It looks to me like what you will need to do is construct the query dynamically and then use
OPEN cursor FOR l_query;
where l_query is the constructed string. This should give you a feel for what you can do:
CREATE OR REPLACE PACKAGE return_id_sal
AUTHID DEFINER
IS
TYPE employee_rt IS RECORD
(
employee_id employees.employee_id%TYPE,
salary employees.salary%TYPE
);
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR;
END return_id_sal;
/
CREATE OR REPLACE PACKAGE BODY return_id_sal
IS
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR
IS
l_return SYS_REFCURSOR;
BEGIN
OPEN l_return FOR
'SELECT employee_id, salary FROM employees ' || append_to_from_in;
RETURN l_return;
END allrows_by;
END return_id_sal;
/
DECLARE
l_cursor SYS_REFCURSOR;
l_row return_id_sal.employee_rt;
BEGIN
l_cursor := return_id_sal.allrows_by ('WHERE department_id = 10');
LOOP
FETCH l_cursor INTO l_row;
EXIT WHEN l_cursor%NOTFOUND;
END LOOP;
END;
/
You will need to take precautions against SQL injection with this sort of code. Certainly a user should never be able to pass SQL text directly to such a function!
You can use also some built-in VARRAY SQL types like SYS.ODCIVARCHAR2LIST or create your own :
CREATE OR REPLACE NONEDITIONABLE TYPE VARCHARLIST
AS VARRAY(32767) OF VARCHAR2(4000);
Then you can use it with SELECT COLUMN_VALUE FROM TABLE(COLLECTION) statement in your cursor:
DECLARE
l_terms SYS.ODCIVARCHAR2LIS; --or VARCHARLIST
CURSOR my_cursor (p_terms IN SYS.ODCIVARCHAR2LIS) IS
SELECT your_column
FROM your_table
WHERE terms in (select COLUMN_VALUE from table (p_terms));
BEGIN
select term
bulk collect into l_terms
from (
select 'term1' term from dual
union all
select 'term2' term from dual
);
FOR my_record IN my_cursor (l_terms) LOOP
--process data from your cursor...
END LOOP;
END;
Is it possible to have multiple tables in one TRIGGER? Let say I have Employee, Skill and Customer Tables and I have Eventlogs table to capture the audit. I tried to add Skill_T but I got ORA-04079 error. Any correction? Thank you!
NOTE: I am using Oracle SQL Developer Oracle11gEE
CREATE OR REPLACE TRIGGER AUDIT_REC
AFTER INSERT OR DELETE OR UPDATE ON EMPLOYEE_T, SKILL_T
FOR EACH ROW
DECLARE
V_LOGID NUMBER;
V_USER VARCHAR(30);
V_DATE VARCHAR(30);
BEGIN
SELECT EVENTLOG_ID_SEQ.NEXTVAL, USER, SYSDATE INTO V_LOGID, V_USER, V_DATE FROM DUAL;
IF INSERTING THEN
INSERT INTO EVENTLOGS(Eventlog_id, User_name, Date_done, Action_done)
VALUES (V_LOGID, V_USER, V_DATE, 'INSERT');
ELSIF DELETING THEN
INSERT INTO EVENTLOGS(Eventlog_id, User_name, Date_done, Action_done)
VALUES (V_LOGID, V_USER, V_DATE, 'DELETE');
ELSIF UPDATING THEN
INSERT INTO EVENTLOGS(Eventlog_id, User_name, Date_done, Action_done)
VALUES (V_LOGID, V_USER, V_DATE, 'UPDATE');
END IF;
END;
/
A DML Trigger is associated (tied to) with only ONE table. It executes when DML is submitted against that table only.
See http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99888
I am trying to populate a array through a select query and then dropping values grabbed in select query.
DECLARE
TYPE name_list is varray(20) of VARCHAR2(30);
existingConstraints name_list:=name_list();
BEGIN
SELECT COUNT(1) INTO v_constraint_exists FROM user_constraints
WHERE constraint_name != 'some_value' AND table_name = 'some_value';
for i in NVL(existingConstraints.FIRST,0)..NVL(existingConstraints.LAST,-1) loop
#set($name=existingConstraints(i))
EXECUTE IMMEDIATE 'ALTER TABLE ${some_value} DROP CONSTRAINT ${name} DROP INDEX';
end loop;
END
But i am getting Exception. Can someone suggest me right approach for the same.
`DECLARE
TYPE name_list is varray(20) of VARCHAR2(30);
existingConstraints name_list:=name_list();
BEGIN
SELECT constraint_name INTO existingConstraints FROM user_constraints
WHERE constraint_name != 'some_value' AND table_name = 'some_value' AND constraint_type='U';
for i in NVL(existingConstraints.FIRST,0)..NVL(existingConstraints.LAST,-1) loop
#set($name=existingConstraints(i))
EXECUTE IMMEDIATE 'ALTER TABLE ${tableName} DROP CONSTRAINT ${name} DROP INDEX';
end loop;
END`
I did it in a slightly different way but problem solved, just for the reference.
DECLARE
TYPE name_list is table of VARCHAR2(30);
v_constraint_exists NUMBER;
existingConstraints name_list:=name_list();
dropConstraintName VARCHAR2(30);
BEGIN
SELECT constraint_name bulk collect INTO existingConstraints FROM user_constraints
WHERE constraint_name != 'some_name' AND table_name = 'some_name' AND constraint_type='U';
for i in NVL(existingConstraints.FIRST,0)..NVL(existingConstraints.LAST,-1) loop
dropConstraintName:=existingConstraints(i);
EXECUTE IMMEDIATE 'ALTER TABLE ${tableName} DROP CONSTRAINT '||dropConstraintName||' DROP INDEX';
end loop;
END
Lets say I have a table as follows--
create table employees
(
eno number(4) not null primary key,
ename varchar2(30),
zip number(5) references zipcodes,
hdate date
);
And I'm trying to create a trigger with--
CREATE OR REPLACE TRIGGER TWELVE_ONE
BEFORE INSERT OR UPDATE
ON EMPLOYEES
FOR EACH ROW
DECLARE
V_DATE VARCHAR2 (10);
BEGIN
SELECT TO_CHAR (SYSDATE, 'hh24:mi:ss') INTO V_DATE FROM DUAL;
IF (V_DATE >= '12:00:01' AND V_DATE < '13:00:00')
THEN
INSERT INTO TABLE ?????
ELSE
ROLLBACK? TERMINATE TRANSACTION?
END IF;
END;
Purpose of the trigger is to allow an insertion/update during 12:00-13:00 and prevent the insertion at any other time. The trigger construction (thanks to #Melkikun) is seems ok. However now I'm facing the following issues--
How is it possible to pass the values here? I mean lets say my create statement is:
Insert into employees Values (1, 'someone', 11111, '17-12-2015')
And lets say the time is 12:30:01 now. How would the trigger perform the insertion without knowing the values?
And lets say the time is now 13:00:1 now. How would the trigger stop/prevent the insertion?
I'm using Oracle SQL Developer 4.02.15
Many Thanks
You just have to do it the other way.
If the time is not correct,then you raise an exception, so the insert won't be done.
CREATE OR REPLACE TRIGGER TWELVE_ONE
BEFORE INSERT OR UPDATE
ON EMPLOYEES
FOR EACH ROW
DECLARE
V_DATE VARCHAR2 (10);
MyException exception;
BEGIN
SELECT TO_CHAR (SYSDATE, 'hh24:mi:ss') INTO V_DATE FROM DUAL;
IF (V_DATE < '12:00:01' OR V_DATE > '13:00:00')
THEN
raise MyException;
END IF;
EXCEPTION
When MyException then
ROLLBACK;
//output message ...
END;
How would the trigger perform the insertion without knowing the values?
The trigger knows the value thanks to :NEW and :OLD.
You normally use the terms in a trigger using :old to reference the old value and :new to reference the new value.So you will have :NEW.eno ,:NEW.ename ...
Here is an example from the Oracle documentation :
CREATE OR REPLACE TRIGGER Print_salary_changes
BEFORE DELETE OR INSERT OR UPDATE ON Emp_tab
FOR EACH ROW
WHEN (new.Empno > 0)
DECLARE
sal_diff number;
BEGIN
sal_diff := :new.sal - :old.sal;
dbms_output.put('Old salary: ' || :old.sal);
dbms_output.put(' New salary: ' || :new.sal);
dbms_output.put_line(' Difference ' || sal_diff);
END;
Here is a code for trigger and it have a for loop. When trigger is fired (INSERT OR UPDATE) there's another table data must include it is MICL_SUP
OPEN projMgrsCursor;
LOOP
FETCH projMgrsCursor INTO projMgr;
select micl_sup_id_seq.nextval into SUPID from dual;
insert into MICL_SUP VALUES ((SUPID), (SELECT SYSDATE FROM DUAL), :NEW.ENTRYADDEDBY_EMP_NO, 3000, 0,projMgr, NULL,:NEW.EMP_NO);
END LOOP;
CLOSE projMgrsCursor;
This is the table structure. Sup_ID primary and unique key . I can't make any changes to table structure
SUP_ID -primary key
ASSIGNED_DATE
ASSIGNED_BY_EMP_NO
AMOUNT_LIMIT
IS_OVVERRIDDEN
SUP_EMP_NO
RTD_EMP
EMP_NO
To enter sup_ID I use select micl_sup_id_seq.nextval into SUPID from dual;
but when I run this code there's an error "RA-00001: unique constraint violated" (this is not a compilation error ) Is there any other way to add sup_ID? Where have I gone wrong?
This question is related with this trigger PlSQL trigger error ORA-0000 ORA-06512:
Why not including calculation of micl_sup_id_seq.nextval into your cursor?
cursor projMgrsCursor is
select b.BU_MEMBER_ID, micl_sup_id_seq.nextval SUPID
from ...
Try rewriting your code as:
DECLARE
nSupid NUMBER;
projMgr VARCHAR2(32767);
BEGIN
OPEN projMgrsCursor;
LOOP
FETCH projMgrsCursor INTO projMgr;
EXIT WHEN projMgrsCursor%NOTFOUND;
select micl_sup_id_seq.nextval into nSUPID from dual;
insert into MICL_SUP
(SUPID, ASSIGNED_DATE, ASSIGNED_BY_EMP_NO, AMOUNT_LIMIT,
IS_OVERRIDDEN, SUP_EMP_NO, RTD_EMP, EMP_NO)
VALUES
(nSupid, SYSDATE, :NEW.ENTRYADDEDBY_EMP_NO, 3000,
0, projMgr, NULL, :NEW.EMP_NO);
END LOOP;
CLOSE projMgrsCursor;
DBMS_OUTPUT.PUT_LINE('Successful completion');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Exception: ' || SQLCODE || ' ' || SQLERRM);
RAISE;
END;
Share and enjoy.