How to disable all triggers that concerns a table in Oracle? - oracle

In Postgresql, if I do ALTER TABLE mytable DISBLE TRIGGERS ALL, all triggers and constraints regarding this table are suspended.
Especially, foreign keys from other tables to mytable are suspended, and I can delete from mytable without problem. I have the risk to break database consistency, but I know what I'm doing, and I must have superuser privileges.
How do I do the same in Oracle ? I am under the impression that ALTER TABLE mytable DISBLE ALL TRIGGERS in Oracle will suspend all trigger and constraints belonging to mytable, but not those that concerns mytable but belong to other tables (especially foreign keys).
Am I right and what would be the way to achieve the same result as in Postgresql in Oracle ?

The syntax does disable triggers in Oracle:
SQL> select trigger_name, status from user_triggers
2 where table_name='TEST'
3 /
TRIGGER_NAME STATUS
------------------------------ --------
TEST_TRIGGER ENABLED
SQL> ALTER TABLE test DISABLE ALL TRIGGERS
2 /
Table altered.
SQL> select trigger_name, status from user_triggers
2 where table_name='TEST'
3 /
TRIGGER_NAME STATUS
------------------------------ --------
TEST_TRIGGER DISABLED
SQL>
However it won't do anything for foreign keys, or indeed any other constraint. That's because Oracle doesn't use triggers to enforce such things. Okay, under the covers constraints and user-defined triggers may share certain low-level kernel code. But at the level we're talking they are two different things.
If you want to disable all foreign keys on a table I'm afraid you'll need to use something like this:
SQL> select constraint_name, status from user_constraints
2 where table_name = 'EMP'
3 and constraint_type = 'R'
4 /
CONSTRAINT_NAME STATUS
------------------------------ --------
FK_DEPTNO ENABLED
SQL> begin
2 for r in ( select constraint_name, status from user_constraints
3 where table_name = 'EMP'
4 and constraint_type = 'R' )
5 loop
6 execute immediate 'alter table emp disable constraint '||r.constraint_name;
7 end loop;
8* end;
9 /
PL/SQL procedure successfully completed.
SQL> select constraint_name, status from user_constraints
2 where table_name = 'EMP'
3 and constraint_type = 'R'
4 /
CONSTRAINT_NAME STATUS
------------------------------ --------
FK_DEPTNO DISABLED
SQL>
This is the sort of thing you'll probably want to wrap in a user-defined function, which takes TABLE_NAME as a parameter. Also you'll need a similar function to re-enable the constraints.

Related

How to use a variable to alter a constraint of a table in PL SQL?

I am trying to get the name of a constraint and then alter a table to remove the constraint. The constraint has not been named so I guess I have no other option. Here is what I tried:
DECLARE
the_variable VARCHAR2(20);
BEGIN
SELECT CONSTRAINT_NAME INTO the_variable
FROM all_constraints
WHERE table_name = 'MY_TABLE'
AND SEARCH_CONDITION_VC = 'format IN (''CSV'', ''PDF'')';
END;
The query above seems to work fine, but when I try to alter the table in this way:
ALTER TABLE SOME_TABLE DROP CONSTRAINT the_variable;
I get this error:
SQL Error [6550] [65000]: ORA-06550: line 14, column 1:
PLS-00103: Encountered the symbol "ALTER"
You can't perform DDL like that; has to be dynamic SQL. Here's an example - you need what's written in line #9:
SQL> create table my_table (id number primary key);
Table created.
SQL> declare
2 the_variable varchar2(30);
3 begin
4 select constraint_name
5 into the_variable
6 from all_constraints
7 where table_name = 'MY_TABLE';
8
9 execute immediate 'alter table my_table drop constraint ' || the_variable;
10 end;
11 /
PL/SQL procedure successfully completed.
SQL> select count(*) from all_constraints where table_name = 'MY_TABLE';
COUNT(*)
----------
0
SQL>

Oracle sql, alter constraint without specifying it's name

I would like to rename a constraint, in oracle database, without specify it's name, but with selecting it's name. I would like to do something like this:
ALTER TABLE O4Y_USER RENAME CONSTRAINT
(SELECT constraint_name
FROM user_constraints
WHERE table_name = 'O4Y_USER'
AND constraint_type = 'P'
) TO 'O4Y_USER_PK';
It is not working, I have the following error
The select alone, is working well, it returns the correct value. How is the correct syntax to do, to work the alter statement?
You can use dynamic SQL. Something like:
DECLARE
p_constraint_name VARCHAR2(30);
p_sql VARCHAR2(4000);
BEGIN
SELECT constraint_name
INTO p_constraint_name
FROM user_constraints
WHERE table_name = 'O4Y_USER'
AND constraint_type = 'P';
p_sql := 'ALTER TABLE O4Y_USER RENAME CONSTRAINT "'
|| p_constraint_name
|| '" TO ''O4Y_USER_PK''';
DBMS_OUTPUT.PUT_LINE( p_sql );
EXECUTE IMMEDIATE p_sql;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE( 'Constraint not found!' );
END;
/
And just the same method using SQL*Plus or similar command line tools.
SQL> create table t ( x int primary key );
Table created.
SQL>
SQL> col cname new_value x
SQL>
SQL> SELECT constraint_name cname
2 FROM user_constraints
3 WHERE table_name = 'T'
4 AND constraint_type = 'P';
CNAME
----------------------------------------------------------------------
SYS_C0068724
SQL>
SQL> ALTER TABLE t RENAME CONSTRAINT &&x to my_new_name;
old 1: ALTER TABLE t RENAME CONSTRAINT &&x to my_new_name
new 1: ALTER TABLE t RENAME CONSTRAINT SYS_C0068724 to my_new_name
Table altered.

Dropping constraints in a PL/SQL loop

I get following error when I am attempting to disable constraints from hr.employees table
Error:
Error report -
ORA-02250: missing or invalid constraint name
ORA-06512: at line 14
02250. 00000 - "missing or invalid constraint name"
*Cause: The constraint name is missing or invalid.
*Action: Specify a valid identifier name for the constraint name.
Following is the code
DECLARE
CURSOR C1 IS SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME ='EMPLOYEES';
v_con_name VARCHAR2(20);
SQL_STATMENT VARCHAR2(100);
BEGIN
SQL_STATMENT := 'ALTER TABLE HR.EMPLOYEES DISABLE CONSTRAINT :A';
OPEN C1;
LOOP
FETCH C1 INTO v_con_name;
EXIT WHEN C1%NOTFOUND;
EXECUTE IMMEDIATE SQL_STATMENT USING v_con_name;
DBMS_OUTPUT.PUT_LINE(v_con_name);
END LOOP;
CLOSE C1;
END;
/
When I comment following line
EXECUTE IMMEDIATE SQL_STATMENT USING v_con_name;
Scripts execute successfully and provide following results
EMP_LAST_NAME_NN
EMP_EMAIL_NN
EMP_HIRE_DATE_NN
EMP_JOB_NN
EMP_SALARY_MIN
EMP_EMAIL_UK
EMP_EMP_ID_PK
EMP_DEPT_FK
EMP_JOB_FK
EMP_MANAGER_FK
PL/SQL procedure successfully completed.
Hence I understand that the cursor construct is fetching the desired constraints name and also outside of this plsql block, I could successfully alter employees table by disabling these constraints.
Please note that I have logged in as HR schema in Oracle 11g R2 XE database
I am not sure why I am getting the missing or invalid constraint name.. thanks to help me here.
You can't use bind variables for the names of database objects (or for DDL in general). You will need to build the entire ALTER statement by concatenating the name. Try something like this:
declare
k_tablename constant user_constraints.table_name%type := 'EMPLOYEES';
begin
for r in (
select constraint_name
, 'alter table ' || c.table_name || ' disable constraint ' || c.constraint_name as sql_statement
from user_constraints c
where table_name = k_tablename
)
loop
execute immediate r.sql_statement;
dbms_output.put_line('Disabled constraint ' || k_tablename || '.' || r.constraint_name);
end loop;
end;
/
Why don't you use this script to generate the DISABLE script?
SELECT 'ALTER TABLE '||OWNER||'.'||TABLE_NAME||' DISABLE CONSTRAINT '||CONSTRAINT_NAME||';' STMNT
FROM DBA_CONSTRAINTS
WHERE
R_CONSTRAINT_NAME IN
(SELECT CONSTRAINT_NAME
FROM DBA_CONSTRAINTS
WHERE CONSTRAINT_TYPE IN ('P','U')
AND OWNER = 'HR'
AND TABLE_NAME IN
(
'EMPLOYEES'
));
Somewhat simpler (& working) then the original attempt:
SQL> create table test (id number constraint pk_test primary key,
2 ime varchar2(20) constraint ch_ime check (ime in ('little', 'foot')));
Table created.
SQL>
SQL> begin
2 for c1 in (select table_name, constraint_name
3 from user_constraints
4 where table_name = 'TEST')
5 loop
6 execute immediate 'alter table ' || c1.table_name ||
7 ' disable constraint ' || c1.constraint_name;
8 end loop;
9 end;
10 /
PL/SQL procedure successfully completed.
SQL> select constraint_name, status From user_constraints where table_name = 'TEST';
CONSTRAINT_NAME STATUS
------------------------------ --------
CH_IME DISABLED
PK_TEST DISABLED
SQL>

Can adding FK or PK constraints invalidate something?

I have a couple of tables with primary-foreign key relations but those constraints do not actually exist. Now I want to add them with an alter table statement.
Will those commands cause any object that depends on the tables to become invalid?
Thanks.
This is a good question. Let's poke the database and see. Here's the set up:
SQL> create table p23 (id number not null, col1 varchar2(10));
Table created.
SQL> create table c23 (id number not null, p_id number not null, col1 varchar2(10));
Table created.
SQL> create or replace procedure tst23
2 is
3 begin
4 insert into p23 values (1, 'ABC');
5 insert into c23 values (11, 1, 'DEF');
6 end;
7 /
Procedure created.
SQL> select status from user_objects where object_name = 'TST23';
STATUS
-------
VALID
SQL>
Everything is copacetic. Now we'll add some constraints.
SQL> alter table p23 add constraint p23_pk primary key (id);
Table altered.
SQL> select status from user_objects where object_name = 'TST23';
STATUS
-------
VALID
SQL> alter table c23 add constraint c23_p23_fk
2 foreign key (p_id) references p23;
Table altered.
SQL> select status from user_objects where object_name = 'TST23';
STATUS
-------
VALID
SQL>
All is still cool. But when we change a table's structure this happens...
SQL> alter table p23 add col2 date;
Table altered.
SQL> select status from user_objects where object_name = 'TST23';
STATUS
-------
INVALID
SQL>
... which is exactly what we would want.
Note that I ran these tests on 11gR2. Oracle introduced fine-grained dependency tracking in 11g, which made programmatic objects more robust when we run DDL on their dependencies. Find out more. So the outcome might be different in earlier versions. It pays to test.
" what is the reason for the procedure to become invalid?"
Structural changes such as adding, modifying or dropping a column potentially have an impact on referencing objects. The procedure had insert statements which didn't specify target columns. So adding a column introduced an ORA-00947: not enough values bug.
But suppose we employed good practice and specified columns?
SQL> create or replace procedure tst23
2 is
3 begin
4 insert into p23 (id, col1) values (1, 'ABC');
5 end;
6 /
Procedure created.
SQL> select status from user_objects where object_name = 'TST23';
STATUS
-------
VALID
SQL> alter table p23 add col4 number;
Table altered.
SQL> select status from user_objects where object_name = 'TST23';
STATUS
-------
VALID
SQL>
Now we're protected by fine-grained dependency tracking. Well, sort of. We shouldn't substitute dependency tracking for impact analysis:
SQL> alter table p23 add col5 date not null;
Table altered.
SQL> select status from user_objects where object_name = 'TST23';
STATUS
-------
VALID
SQL>
The procedure has a VALID state but it will still fail when we run it, because it doesn't populate the new mandatory column.

Extra entries in recycle bin when table dropped

I have created a table TESTTABLE28.
Then I dropped the table.DROP TABLE TESTTABLE28;
The show parameter recyclebin; value was set to on.
When I checked the Recycle Bin, observed some other entries along with TESTTABLE28 are listed,
Once I flashback table TESTTABLE28 to before drop; to restore the table, these extra entries are also moved.
What is this values and why it didn't come, when I dropped another table TESTTABLE31 which has only one varchar2 column?
UPDATE
Also how can I restore the constraints which is showing BIN$5lpccCurTNWwCbOSxCK29w==$1 now instead of TESTTABLE28_PK.
Because you have LOB columns in your table you also have segments and indices to them:
SQL> create table t_lb (x int, y clob, z blob);
SQL> col column_name format a10
SQL> col segment_name format a30
SQL> col index_name format a30
SQL> select column_name, segment_name, index_name from user_lobs
2 where table_name = 'T_LB'
3 /
COLUMN_NAM SEGMENT_NAME INDEX_NAME
---------- ------------------------------ ------------------------------
Y SYS_LOB0000701495C00002$$ SYS_IL0000701495C00002$$
Z SYS_LOB0000701495C00003$$ SYS_IL0000701495C00003$$
SQL> show parameter recyclebin
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
recyclebin string ON
SQL> drop table t_lb;
SQL> col object_name format a30
SQL> col type format a30
SQL> select object_name, type from recyclebin
2 /
OBJECT_NAME TYPE
------------------------------ ------------------------------
BIN$8hw9X/AeBmngQ0QTGKxsAQ==$0 TABLE
SYS_LOB0000701495C00003$$ LOB
SYS_LOB0000701495C00002$$ LOB
SYS_IL0000701495C00003$$ LOB INDEX
SYS_IL0000701495C00002$$ LOB INDEX
As of constraint/index restoring - you should rename them back:
SQL> create table t (x int, constraint t_pk primary key(x))
2 /
SQL> drop table t;
SQL> select object_name, type from recyclebin;
OBJECT_NAME TYPE
------------------------------ ------------------------------
BIN$8hw9X/AiBmngQ0QTGKxsAQ==$0 TABLE
BIN$8hw9X/AhBmngQ0QTGKxsAQ==$0 INDEX
SQL> flashback table t to before drop;
SQL> select constraint_name, index_name, constraint_type from
2 user_constraints where table_name = 'T';
CONSTRAINT_NAME INDEX_NAME C
------------------------------ ------------------------------ -
BIN$8hw9X/AgBmngQ0QTGKxsAQ==$0 BIN$8hw9X/AhBmngQ0QTGKxsAQ==$0 P
SQL> begin
2 for cur in (select constraint_name, index_name
3 from user_constraints where table_name = 'T'
4 and constraint_type = 'P') loop
5 execute immediate
6 'alter table t rename constraint "'||cur.constraint_name||
7 '" to t_pk';
8 execute immediate
9 'alter index "'||cur.index_name||'" rename to t_pk';
10 end loop;
11 end;
12 /
SQL> select constraint_name, index_name from user_constraints
2 where table_name = 'T';
CONSTRAINT_NAME INDEX_NAME
------------------------------ ------------------------------
T_PK T_PK

Resources