First I created a temporary table
CREATE GLOBAL TEMPORARY TABLE TMP ON COMMIT PRESERVE ROWS AS
SELECT *
FROM A
then
INSERT INTO TMP
SELECT *
FROM B
COMMIT
finally
CREATE INDEX IDX ON TMP (COLA, COLB, COLC);
Upon creating the index, I got the following error
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
I followd these steps in the same session.
What I want to do(with temporary table) is
Disable/Drop index
Insert large data
Enable/Create index
How can I acheive this?
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
This error occurs when it is tried to perform a DDL on a global temporary table with on commit preserve rows when the session trying to do the DDL has already made a DML on the table.
In order to do a DDL, the table must first be either truncated or the session must be exited.
http://www.adp-gmbh.ch/ora/err/ora_14452.html
I have to admit to being surprised by this. The only solution I have come up with so far is to re-establish the session
SQL> drop table tmp;
Table dropped.
SQL>
SQL> CREATE GLOBAL TEMPORARY TABLE TMP ON COMMIT PRESERVE ROWS AS
2 SELECT *
3 FROM emp
4 ;
Table created.
SQL>
SQL>
SQL> INSERT INTO TMP
2 SELECT *
3 FROM emp
4 ;
14 rows created.
SQL>
SQL> COMMIT
2 ;
Commit complete.
SQL>
SQL> connect scott/tiger
Connected.
SQL>
SQL> CREATE INDEX IDX ON TMP (empno);
Index created.
When you insert lines into a temp table it gets locked and the index can't be created.
You should create the index before inserting the data:
CREATE GLOBAL TEMPORARY TABLE tmp ON COMMIT PRESERVE ROWS AS
SELECT *
FROM scott.dept;
CREATE INDEX idx ON
tmp (deptno);
ora-14452: tentativa de criar, alterar ou eliminar um índice em uma tabela temporária que já está sendo usada
14452. 00000 - "attempt to create, alter or drop an index on temporary table already in use"
*Cause: An attempt was made to create, alter or drop an index on temporary
table which is already in use.
*Action: All the sessions using the session-specific temporary table have
to truncate table and all the transactions using transaction
specific temporary table have to end their transactions.
TRUNCATE TABLE tmp;
Table TMP truncado.
CREATE INDEX idx ON tmp (deptno);
Index idx criado.
INSERT INTO tmp
SELECT *
FROM scott.dept;
4 linhas inserido.
COMMIT;
Commit concluído.
Related
I have a table and I want to increment a column by 1 when I insert a row into the same table.
Table users - when I insert first row value of idusers is 1, and in second row value is 2 ....
This is the table
USERS
EMAIL primary key
USERNAME
PASSWORD
IDUSER and this the column I want to be AUTO_INCREMENT
I have tried this code
CREATE SEQUENCE seq_person
MINVALUE 1
START WITH 1
INCREMENT BY 1
CACHE 10;
create or replace trigger incrementIdUser
before insert on users
for each row
begin
select seq_person.nextval into :new.IDUSER from users;
end;
But I get an error when I insert a row:
Erreur lors de l'enregistrement des modifications de la table "SOCIAL"."USERS" :
Ligne 1 : ORA-01403: no data found
ORA-01403: no data found
ORA-06512: at "SOCIAL.INCREMENTIDUSER", line 2
ORA-04088: error during execution of trigger 'SOCIAL.INCREMENTIDUSER'
ORA-06512: at line 1
Not like that, but
create or replace trigger incrementIdUser
before insert on users
for each row
begin
:new.iduser := seq_person.nextval;
end;
Code you wrote selects from users table (which is empty, hence NO_DATA_FOUND). If it contained more than a single row, you'd get TOO_MANY_ROWS (as you're selecting into a scalar variable (:new.iduser). Finally, there's danger of mutating table error as you can't select from a table which is just being modified (in this trigger type).
Insetead of select seq_person.nextval into :new.IDUSER from users; to assign sequence value into iduser you need to use :new.IDUSER :=seq_person.nextval;
create or replace trigger incrementIdUser
before insert on users
for each row
begin
:new.IDUSER :=seq_person.nextval;
end;
You get that error because there are zero rows in the USERS table so SELECT ... FROM USERS returns no rows.
What you want is to either use a table that will always return a single row (which, in Oracle, is the DUAL table):
create or replace trigger incrementIdUser
before insert on users
for each row
begin
select seq_person.nextval into :new.IDUSER from DUAL;
end;
Or, the better solution, is to not use an SQL statement and use pure PL/SQL:
create or replace trigger incrementIdUser
before insert on users
for each row
begin
:new.IDUSER := seq_person.nextval;
end;
Instead of using a trigger, you should use an identity column in the create table statement:
create table users
(iduser integer generated by default on null as identity (nomaxvalue nocache order),
...);
I am new to SQL. I want to create a (global or not) temporary table in Oracle SQL which will include a simple selection of data of the form SELECT * FROM tbl_NAME WHERE... and which after the end of my session will be deleted (just like the MSFT SQL temporary tables of the form ##tbl_NAME).
I found online that one way to do it is:
CREATE GLOBAL TEMPORARY TABLE tmp_table
SELECT * FROM tbl_NAME WHERE conditions.
ON COMMIT PRESERVE ROWS;
although I get the error ORA-00904: invalid identifier
I also found that another alternative is
CREATE PRIVATE TEMPORARY TABLE tmp_table AS
SELECT * FROM tbl_NAME WHERE conditions;
which gives the error ORA-00905: missing keyword.
Please note that I already know that one alternative that works is:
DROP TABLE tmp_table;
CREATE TABLE tmp_table AS
SELECT * FROM tbl_NAME;
DROP TABLE tmp_table;
What you want to do with rows comes first; SELECT comes next:
SQL> create global temporary table gtt_dept
2 on commit preserve rows --> first
3 as
4 select * from dept; --> next
Table created.
SQL>
The below format you had shown works in TERADATA
CREATE GLOBAL TEMPORARY TABLE tmp_table
SELECT * FROM tbl_NAME WHERE conditions.
ON COMMIT PRESERVE ROWS;
In Oracle it works like this
create global temporary table gtt_dept
on commit preserve rows
as
select * from dept;
How to truncate any table using its synonym in oracle?
-- in Server_A
Create Table table_a ( col int);
-- in server_B
CREATE SYNONYM syn_table_a FOR table_a#dblink_server_a;
--insert into
INSERT INTO syn_table_a values (1);
--Truncate
How to truncate table using synonym only?.
A truncate statement cannot be used on a synonym.
Synonyms cannot be used in a drop table, drop view or truncate
table/cluster statements. If this is tried, it results in a ORA-00942:
table or view does not exist
For example,
SQL> CREATE TABLE t(col NUMBER);
Table created.
SQL>
SQL> CREATE SYNONYM t_syn FOR t;
Synonym created.
SQL>
SQL> TRUNCATE TABLE t_syn;
TRUNCATE TABLE t_syn
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL>
You could use dynamic SQL to do it, e.g.:
declare
d varchar2(1000);
begin
select 'TRUNCATE TABLE "' || table_owner || '"."' || table_name || '"'
into d
from all_synonyms
where synonym_name = 'MYSYNONYM';
execute immediate d;
end;
If the table is accessed via a database link, this will not work. In that case, you could create a procedure on the remote instance that does the truncate, then call that procedure across the database link, e.g.
begin
truncate_my_table#dblinkname;
end;
In Oracle, you can also get ORA-14410 while trying to drop/truncate a table using synonym.
The alert log:
ORA-00604: error occurred at recursive SQL level 1
ORA-14410: RPI LOCK TABLE issued to table referenced through synonym
Follow the above dynamic SQl to drop/truncate it.
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
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