Oracle 9i auto increment trigger/sequence doesnt work - sql

The following SQL, upon being executed on an Oracle 9i server, yields the the error " ORA-04098: trigger 'DBO.WTF_TRIGGER' is invalid and failed re-validation".
DROP TABLE "DBO".WTF;
CREATE TABLE "DBO".WTF
(id NUMBER PRIMARY KEY,
name VARCHAR2(30));
CREATE SEQUENCE "DBO".WTF_sequence
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER "DBO".WTF_trigger
BEFORE INSERT
ON "DBO".WTF
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT "DBO".WTF_sequence.nextval INTO :NEW.id FROM dual;
END;
INSERT INTO "DBO".WTF (name) VALUES ('asd');
Any ideas?

As APC points out, it would be helpful to do a SHOW ERRORS in SQL*Plus to print out the errors. The code you posted works perfectly for me if I create a DBO user with appropriate privileges.
SQL> conn / as sysdba
Connected.
SQL> create user dbo identified by dbo;
User created.
SQL> grant connect, resource, unlimited tablespace to dbo;
Grant succeeded.
SQL> conn dbo/dbo
Connected.
SQL> DROP TABLE "DBO".WTF;
DROP TABLE "DBO".WTF
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL>
SQL> CREATE TABLE "DBO".WTF
2 (id NUMBER PRIMARY KEY,
3 name VARCHAR2(30));
Table created.
SQL>
SQL> CREATE SEQUENCE "DBO".WTF_sequence
2 START WITH 1
3 INCREMENT BY 1;
Sequence created.
SQL>
SQL> CREATE OR REPLACE TRIGGER "DBO".WTF_trigger
2 BEFORE INSERT
3 ON "DBO".WTF
4 REFERENCING NEW AS NEW
5 FOR EACH ROW
6 BEGIN
7 SELECT "DBO".WTF_sequence.nextval INTO :NEW.id FROM dual;
8 END;
9 /
Trigger created.
SQL> INSERT INTO "DBO".WTF (name) VALUES ('asd');
1 row created.
SQL> select * from wtf;
ID NAME
---------- ------------------------------
1 asd

Related

How can I get the table name in a Oracle trigger function?

How can I get the table name inside trigger function?
Something similar to TG_TABLE_NAME in Postgres, like this
Oracle 10g or above.
That's user_triggers view (if I understood the question correctly).
SQL> create table test (id number, name varchar2(20));
Table created.
SQL> create or replace trigger trg_test
2 before insert on test
3 for each row
4 begin
5 null;
6 end;
7 /
Trigger created.
SQL> select trigger_name, table_name from user_triggers;
TRIGGER_NAME TABLE_NAME
------------------------------ ------------------------------
TRG_TEST TEST --> this is the one I've just created
TRG_AIUD_EMP EMPLOYEES
SQL>

Prevent Drop View in Oracle

How to prevent a user from not dropping a view even he/she has previlige to do so? I have a view being used by an application. However, it was dropped by a user a couple times. Is there something like REVOKE DROP ANY VIEW? Do I have to use a trigger for that?
A trigger might help. Here's an example.
First, a few objects to be dropped:
SQL> create table test as select * From emp where 1 = 2;
Table created.
SQL> create or replace view v_dept as select * From dept;
View created.
SQL>
I don't want to allow V_DEPT to be dropped, so:
SQL> create or replace trigger trg_drop
2 before drop on schema
3 declare
4 l_name varchar2(30);
5 begin
6 select ora_dict_obj_name
7 into l_name
8 from dual;
9 if l_name = 'V_DEPT' then
10 raise_application_error(-20001, 'Forbidden');
11 end if;
12 end;
13 /
Trigger created.
Testing:
SQL> drop view v_dept;
drop view v_dept
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: Forbidden
ORA-06512: at line 8
SQL> drop table test;
Table dropped.
SQL>

Disable trigger in another db(Oracle)

Can I create a procedure that disables a trigger in another database? I mean, can I disable it with a database link?
I need it for importing data into a data warehouse
Yes, you can do that. Here's how.
In a remote database (called ORCL), I'm creating a table and a trigger:
SQL> create table test (id number);
Table created.
SQL> create or replace trigger trg_test
2 before insert on test
3 for each row
4 begin
5 null;
6 end;
7 /
Trigger created.
Furthermore, in the same (remote) database, I'm creating a procedure which will disable that trigger. It'll use dynamic SQL as you can't execute DDL in PL/SQL just like that:
SQL> create or replace procedure p_disable_trg_test as
2 begin
3 execute immediate 'alter trigger trg_test disable';
4 end;
5 /
Procedure created.
Now, in a local database, I'm creating a database link to the ORCL database:
SQL> create database link dbl_scott_orcl
2 connect to scott
3 identified by tiger
4 using 'orcl';
Database link created.
Does it work?
SQL> select * from dual#dbl_scott_orcl;
D
-
X
Yes, it does. Fine. Now, all you have to do is to call the remote procedure from the local database:
SQL> begin
2 p_disable_trg_test#dbl_scott_orcl;
3 end;
4 /
PL/SQL procedure successfully completed.
SQL>
Let's check the remote database's trigger status:
SQL> select trigger_name, status from user_Triggers where trigger_name = 'TRG_TEST';
TRIGGER_NAME STATUS
------------------------------ --------
TRG_TEST DISABLED
SQL>
DISABLED, as expected.

Create Auto Sequence text and number in oracle 11g

How I do create column ID with value JASG1?
I am only find example like this :
select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job
Although what you wrote probably works (if there's a sequence named MTJ_ID_SEQ, you have a privilege to select from it; the same goes for the TALEND_JOB table), I'd say that it isn't what you should use.
Here's why: I'll create a table and a sequence. Table will be pre-populated with some IDs (just to put something in there).
SQL> create sequence mtj_id_seq;
Sequence created.
SQL> create table talend_job as
2 select rownum id from dept;
Table created.
SQL> select * from talend_job;
ID
----------
1
2
3
4
OK; 4 rows so far. Now, run your SELECT:
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG1
JASG2
JASG3
JASG4
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG5
JASG6
JASG7
JASG8
SQL>
See? You didn't get only 1 JASGx value, but as many as number of rows in the TALEND_JOB table. If there was a million rows, you'd get a million JASGx rows as well.
Therefore, maybe you meant to use DUAL table instead? E.g.
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from dual;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG9
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from dual;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG10
SQL>
See? Only one value.
Also, notice that sequences will provide unique values, but you can't rely on them being gapless.
As you mentioned "how to create column ID" - one option is to use a trigger. Here's an example:
SQL> create table talend_job (id varchar2(20), name varchar2(20)
Table created.
SQL> create or replace trigger trg_bi_tj
2 before insert on talend_job
3 for each row
4 begin
5 :new.id := 'JASG' || mtj_id_seq.nextval;
6 end;
7 /
Trigger created.
Let's insert some names; IDs should be auto-populated by the trigger:
SQL> insert into talend_job (name) values ('littlefoot');
1 row created.
SQL> insert into talend_job (name) values ('Ishak');
1 row created.
SQL> select * From talend_job;
ID NAME
-------------------- --------------------
JASG11 littlefoot
JASG12 Ishak
SQL>
OK then; now you have some more info - read and think about it.
By the way, what is the "compiler-errors" tag used for? Did you write any code and it failed? Perhaps you'd want to share it with us.

IF Statement inside Trigger Clause

I want to use an if statement inside trigger but the value if comparison will come from an other select statement.
I have done the following:
create or replace
Trigger MYTRIGGER
After Insert On Table1
Referencing Old As "OLD" New As "NEW"
For Each Row
Begin
Declare Counter Int;
Select Count(*) From Table2 Where Table2."Email" = :New.U_MAIL Into Counter;
IF Counter < 1 THEN
//INSERT Statement here...
END IF;
End;
My logic is simple, if same email user exists, insert will not work.
Above code did not work. How can we do this?
A few syntax errors. Would be closer to something like this:
create or replace
Trigger MYTRIGGER
After Insert On Table1
Referencing Old As "OLD" New As "NEW"
For Each Row
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_count
FROM Table2
WHERE Email = :New.U_MAIL
;
IF v_count > 0
THEN
RAISE_APPLICATION_ERROR(-20000, 'Not inserted...');
END IF;
END;
Your approach is wrong. Referential integrity should not be made using triggers, it just cannot work as required. See example:
Connected to Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
Connected as test#soft12c1
SQL> create table mail_1 (email varchar2(100));
Table created
SQL> create table mail_2 (email varchar2(100));
Table created
SQL> create trigger mail_1_check
2 before insert on mail_1
3 for each row
4 declare
5 cnt integer;
6 begin
7 select count(*) into cnt from mail_2 where email = :new.email;
8 if cnt > 0 then
9 raise_application_error(-20100, 'Email already exists');
10 end if;
11 end;
12 /
Trigger created
SQL> insert into mail_2 values ('president#gov.us');
1 row inserted
SQL> insert into mail_1 values ('king#kingdom.en');
1 row inserted
SQL> insert into mail_1 values ('president#gov.us');
ORA-20100: Email already exists
ORA-06512: at "TEST.MAIL_1_CHECK", line 6
ORA-04088: error during execution of trigger 'TEST.MAIL_1_CHECK'
It looks like trigger works right, but it's not true. See what happens when several users will works simultaneously.
-- First user in his session
SQL> insert into mail_2 values ('dictator#country.by');
1 row inserted
-- Second user in his session
SQL> insert into mail_1 values ('dictator#country.by');
1 row inserted
-- First user is his session
SQL> commit;
Commit complete
-- Second user is his session
SQL> commit;
Commit complete
-- Any user in any session
SQL> select * from mail_1 natural join mail_2;
EMAIL
--------------------------------------------------------------------------------
dictator#country.by
If using triggers for this task, you should serialize any attempts to use this data, say, execute LOCK TABLE IN EXCLUSIVE MODE unless commit. Generally it's a bad decision. For this concrete task you can use much better approach:
Connected to Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
Connected as test#soft12c1
SQL> create table mail_1_2nd(email varchar2(100));
Table created
SQL> create table mail_2_2nd(email varchar2(100));
Table created
SQL> create materialized view mail_check
2 refresh complete on commit
3 as
4 select 1/0 data from mail_1_2nd natural join mail_2_2nd;
Materialized view created
OK. Let's see, what if we try to use same email:
-- First user in his session
SQL> insert into mail_1_2nd values ('dictator#gov.us');
1 row inserted
-- Second user in his session
SQL> insert into mail_2_2nd values ('dictator#gov.us');
1 row inserted
SQL> commit;
Commit complete
-- First user in his session
SQL> commit;
ORA-12008: error in materialized view refresh path
ORA-01476: divisor is equal to zero
SQL> select * from mail_1_2nd natural join mail_2_2nd;
EMAIL
--------------------------------------------------------------------------------
no rows selected