Is there some equivalent to the Mysql specific instruction that disable the check of the foreign keys constraints ?
SET FOREIGN_KEY_CHECKS = 0;
There is no command in Oracle that will disable all constraints at once.
However it seems you want to disable constraints in the context of dropping tables. In that case you can use the CASCADE CONSTRAINTS clause to drop the referencing constraints from other tables along with the table being dropped.
Here's an example:
SQL> CREATE TABLE t1 (ID NUMBER PRIMARY KEY);
Table created
SQL> CREATE TABLE t2 (ID NUMBER REFERENCES t1);
Table created
SQL> INSERT INTO t1 VALUES (1);
1 row inserted
SQL> INSERT INTO t2 VALUES (1);
1 row inserted
SQL> -- this fails because of the foreign key
SQL> DROP TABLE t1;
ORA-02449: unique/primary keys in table referenced by foreign keys
SQL> DROP TABLE t1 CASCADE CONSTRAINTS;
Table dropped
SET FOREIGN_KEY_CHECKS = 0; is session based. In an Oracle context I can only imagine you needing to do this when you have circular references.
You've commented that this is what you want to do:
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE table1;
DROP TABLE table2;
SET FOREIGN_KEY_CHECKS = 1;
I'm assuming that this means that TABLE1 has a foreign key referencing TABLE2 and TABLE2 has a foreign key referencing TABLE1.
If this is the case then Moudiz's answer is correct. You want to disable the foreign keys before dropping the table:
alter table table1 disable constraint <constraint_name>;
alter table table2 disable constraint <constraint_name>;
drop table table1;
drop table table2;
There's no point disabling all foreign keys for the length of the session, you're only interested in two of them, both of which will be dropped with the table.
You don't want to ever disable all foreign keys.
The only other context I can think of this in is if you want to insert something into your circular reference, in which case you would declare the constraint as DEFERRABLE. This means that the constraint check is done at the end of the transaction rather than on DML being performed, see the documentation.
If your references aren't circular then simply drop the tables in the other order.
IF Your asking for a query to disable a foreign key then try this :
ALTER TABLE mytable
disable CONSTRAINT fk_mytable;
Related
I have created two tables:
Create Table Dept
(Department_id number Constraint Depart_id_pk Primary Key
,Department_name varchar2(20));
Create table Emp
(Emp_id number Constraint Empl_id_pk Primary Key
,First_name varchar2(10)
,salary number
,Department_id number
,Constraint depart_id_fk Foreign Key (department_id)
References Dept (Department_id) on delete set null);
Then I have inserted some records in dept and Emp table. But when I try to drop dept table, instead of setting null in Emp.department_id column it shows error like this:
SQL> Drop Table Dept;
Drop Table Dept
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
The foreign key's clause say "on delete set null". Delete is a DML operation, and had you attempted to delete rows from the dept table, the corresponding emp rows would have been updated with a null dept_id.
But this isn't the case - you tried to drop the entire table, a DDL operation. This isn't allowed, because you'd be leaving behind constraints on the emp table that reference a table that no longer exists. If you want to drop these constraints too, you can use a cascade constraints clause:
DROP TABLE dept CASCADE CONSTRAINTS
I am trying to add UNIQUE KEY on a previously existing table with duplicate records by setting ENABLE NOVALIDATE.
But I am getting ORA-02299: cannot validate (my_owner.my_key_UK ) - duplicate keys found
ALTER TABLE my_owner.my_table
ADD CONSTRAINT my_key_UK UNIQUE (ID1,ID2)
ENABLE NOVALIDATE;
A unique constraint uses an index to enforce the noduplicates rule. By default it will create a unique index (makes sense right?). It is this index creation which is hurling ORA-02299.
However, if this is an existing index on the constrained columns the constraint will use that. The good news is, the index doesn't need to be unique for the constraint to use it.
So what you need to do is build a non-unique index first:
create index whatever_idx on my_table (ID1,ID2);
Then you will be able to create your constraint:
ALTER TABLE my_owner.my_table
ADD CONSTRAINT my_key_UK UNIQUE (ID1,ID2)
ENABLE NOVALIDATE;
You can check this by querying the data dictionary:
select uc.constraint_name
, uc.constraint_type
, uc.index_name
, ui.uniqueness as idx_uniqueness
from user_constraints uc
join user_indexes ui
on ui.index_name = uc.index_name
where uc.table_name = 'MY_TABLE'
Oracle ensure unique values using indexes. And if you create unique constrains db automatic creates unique index. Workaround is add DEFERRABLE options. In this case oracle creates normal index. Check example.
create table table_abc (a number,b number);
insert into table_abc values(1,1);
insert into table_abc values(1,2);
ALTER TABLE table_abc ADD CONSTRAINT my_key_a UNIQUE (a) DEFERRABLE enable novalidate; -- no error but in table nonunique values
ALTER TABLE table_abc ADD CONSTRAINT my_key_b UNIQUE (b) ENABLE NOVALIDATE; --no error
select * from user_indexes where table_name ='TABLE_ABC';
Lets say i have a table with the following definition
create table dummy (col1 number(9) not null)
All the values in this dummy.col1 are 7 digit long. Now i want to reduce the length of this column from 9 - 7 using alter command. Oracle gives me error that column to be modified must be empty to decrease precision or scale. Makes sense.
I want to ask is there any work around to reduce the column size?
I can't delete the values in the column.
I can't copy values from this column to another since it has trillions of data.
The column size has no relationship to how the data is physically stored (they are variable length)
e.g. '23' in a number(2) will take exactly the same space if stored in a number(38)
It is purely a constraint on the maximum number that can be stored in the column therefore you could just add a constraint on the column:
ALTER TABLE dummy ADD
CONSTRAINT c1
CHECK (col1 < 9999999)
ENABLE
VALIDATE;
if you want it to go a little quicker change VALIDATE to NOVALIDATE obviously this will not check the validity of the existing data.
Kevin's answer is excellent.
The only other way to do it is to
rename the existing column,
create a new column with the old name and the new size,
issue an update statement to populate the new field (which you said you cannot do)
and then drop the renamed column.
Are you sure you cannot find some downtime one weekend to perform this task ?
Solution #1
My solution below keeps the original column order.
I found that to be important, especially if there are canned SQL statements out
there (middle tier, client tier) that point back to your database that do implicit
SELECTs.
i.e.
SELECT *
FROM tableName
WHERE ...;
INSERT INTO copyTableName(column1,column2,column3,...)
SELECT *
FROM tableName
WHERE ...;
Here goes:
Generate the DDLs for
1. The table containing the column you intend to resize
2. All the relationship constraints, indexes, check constraints, triggers that reference that table.
3. All the foreign keys of other tables that reference the primary key of this table.
Make sure each table-referencing-object DDL is stand-alone, separate from the
CREATE TABLE DDL.
You'll have something like
/* 1. The table containing the column you intend to resize */
CREATE TABLE tableName
(
column1 TYPE(size) [DEFAULT value] [NOT] NULL,
column2 TYPE(size) [DEFAULT value] [NOT] NULL,
column3 TYPE(size) [DEFAULT value] [NOT] NULL,
...
)
TABLESPACE tsName
[OPTIONS];
/* 2. All the relationship constraints, indexes, check constraints, triggers that reference that table. */
CREATE INDEX indexName ON tableName
(column1)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE INDEX compositeIndexName ON tableName
(column1,column2,...)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CHECK (column4 IS NOT NULL));
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
ALTER TABLE tableName ADD (
CONSTRAINT fkName
FOREIGN KEY (column2)
REFERENCES otherTable (column2));
/* 3. All the foreign keys of other tables that reference the primary key of this table. */
ALTER TABLE otherTableName ADD (
CONSTRAINT otherTableFkName
FOREIGN KEY (otherTableColumn2)
REFERENCES tableName (column1));
Copy out just the CREATE TABLE statement, change the table name and
reduce the size of the column you wish to modify:
CREATE TABLE tableName_YYYYMMDD
(
column1 TYPE(size) [DEFAULT value] [NOT] NULL,
column2 TYPE(reducedSize) [DEFAULT value] [NOT] NULL,
column3 TYPE(size) [DEFAULT value] [NOT] NULL,
...
)
TABLESPACE tsName
[OPTIONS];
Insert the data from tableName into tableName_YYYYMMDD:
INSERT /* APPEND */ INTO tableName_YYYYMMDD(
column1 ,
column2 ,
column3 ,
... )
SELECT
column1 ,
column2 ,
column3 ,
...
FROM tableName;
COMMIT;
Drop all objects referencing the original table.
Also, drop all foreign keys that reference the tableName primary key pkName.
Don't worry, you've saved the DDL so you'll be able to recreate them.
Notice that I drop indexes after copying the data out of tableName.
I do this because perhaps one of the indexes will be used in the
above SELECT so that operation will complete faster.
DROP INDEX indexName ;
DROP INDEX compositeIndexName ;
DROP UNIQUE INDEX pkName ;
ALTER TABLE tableName DROP CONSTRAINT pkName ;
ALTER TABLE tableName DROP CONSTRAINT fkName ;
ALTER TABLE otherTableName DROP CONSTRAINT otherTableFkName ;
Drop the original table.
DROP TABLE tableName;
Rename the new table.
ALTER TABLE tableName_YYYYMMDD RENAME TO tableName;
Recreate all referencing objects from the DDL statements you saved before.
/* 2. All the relationship constraints, indexes, check constraints, triggers that reference that table. */
CREATE INDEX indexName ON tableName
(column1)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE INDEX compositeIndexName ON tableName
(column1,column2,...)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CHECK (column4 IS NOT NULL));
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
ALTER TABLE tableName ADD (
CONSTRAINT fkName
FOREIGN KEY (column2)
REFERENCES otherTable (column2));
/* 3. All the foreign keys of other tables that reference the primary key of this table. */
ALTER TABLE otherTableName ADD (
CONSTRAINT otherTableFkName
FOREIGN KEY (otherTableColumn2)
REFERENCES tableName (column1));
Solution #2
Keep the column order but do not rebuild non-unique-used-by-PK indexes that might contain column2.
ALTER TABLE tableName ADD (column2Copy TYPE(reducedSize));
UPDATE tableName SET column2Copy = column2;
ALTER TABLE tableName MODIFY (column2 TYPE(size) NULL);
ALTER TABLE tableName DROP CONSTRAINT pkName;
DROP INDEX pkName;
UPDATE tableName SET column2 = null;
ALTER TABLE tableName MODIFY (column2 TYPE(reducedSize));
UPDATE tableName SET column2 = column2Copy;
ALTER TABLE tableName DROP COLUMN column2Copy;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
COMMIT;
I'm using Oracle 10g Express and trying to delete records from tables with bi-directional constraints. I'm trying to un-thread hundreds of tables and dependencies generated via Hibernate (which can't be changed at this point), but here is an extremely simplified example:
create table TableA (id number(19,0) not null, ..., rTableA_id number(19,0), primary key (id));
create table TableB (id number(19,0) not null, ..., rTableB_id number(19,0), primary key (id));
alter table TableA add constraint FKA1 foreign key (rTableA_id) references TableB;
alter table TableB add constraint FKB1 foreign key (rTableB_id) references TableA;
Trying to delete entries from either table returns the following:
EDIT: This happens in my case with foreign keys prefixed with SYS_
ORA-02292: integrity constraint (XXX.FKA1) violated - child record found
I've also tried to disable constraints but all attempts are futile:
ORA-02297: cannot disable constraint (XXX.FKA1) - dependencies exist
I have to wonder how your data got in this state in the first place, since your foreign keys are not null. If both tables were empty to start with, you'd never be able to insert a row into either table.
Ignoring that for a moment, recreating your scenario, I have no problem disabling the constraints:
CREATE TABLE tablea(id NUMBER(19, 0) NOT NULL,
rtablea_id NUMBER(19, 0) NOT NULL,
PRIMARY KEY(id))
/
CREATE TABLE tableb(id NUMBER(19, 0) NOT NULL,
rtableb_id NUMBER(19, 0) NOT NULL,
PRIMARY KEY(id))
/
INSERT INTO tablea
VALUES (1, 2)
/
INSERT INTO tableb
VALUES (2, 1)
/
ALTER TABLE tablea ADD CONSTRAINT fka1
FOREIGN KEY (rtablea_id)
REFERENCES tableb
/
ALTER TABLE tableb ADD CONSTRAINT fkb1
FOREIGN KEY (rtableb_id)
REFERENCES tablea
/
ALTER TABLE tablea MODIFY CONSTRAINT fka1 DISABLE
/
ALTER TABLE tableb MODIFY CONSTRAINT fkb1 DISABLE
/
delete tablea
/
delete tableb
/
commit
/
Result:
Table created.
Table created.
1 row created.
1 row created.
Table altered.
Table altered.
Table altered.
Table altered.
1 row deleted.
1 row deleted.
Commit complete.
I'm not sure how you'd get a ORA-02297 error when attempting to disable a foreign key. That error is typically seen when disabling a primary or unique key that a foreign key relies upon.
I suspect what you really want to do is set the constraints to initially deferred. This would allow you to perform inserts and deletes to each table individually, as long as the corresponding row was updated or deleted before the transaction is commited:
CREATE TABLE tablea(id NUMBER(19, 0) NOT NULL,
rtablea_id NUMBER(19, 0) NOT NULL,
PRIMARY KEY(id))
/
CREATE TABLE tableb(id NUMBER(19, 0) NOT NULL,
rtableb_id NUMBER(19, 0) NOT NULL,
PRIMARY KEY(id))
/
ALTER TABLE tablea ADD CONSTRAINT fka1
FOREIGN KEY (rtablea_id)
REFERENCES tableb
INITIALLY DEFERRED
/
ALTER TABLE tableb ADD CONSTRAINT fkb1
FOREIGN KEY (rtableb_id)
REFERENCES tablea
INITIALLY DEFERRED
/
INSERT INTO tablea
VALUES (1, 2)
/
INSERT INTO tableb
VALUES (2, 1)
/
INSERT INTO tableb
VALUES (3, 1)
/
COMMIT
/
DELETE tableb
WHERE id = 2
/
UPDATE tablea
SET rtablea_id = 3
WHERE id = 1
/
COMMIT
/
Result:
Table created.
Table created.
Table altered.
Table altered.
1 row created.
1 row created.
1 row created.
Commit complete.
1 row deleted.
1 row updated.
Commit complete.
Are you sure that Hibernate cannot be told to create the constraints as deferrable? If the DDL doesn't use the DEFERRABLE keyword, the constraints will be non-deferrable by default. That is going to mean that you won't be able to delete the data. If you have a schema with circular references, you would always want to declare your foreign key constraints to be deferrable.
You could drop the constraints, delete the data, and then re-create the constraints (either using Hibernate's DDL or by adding the INITIALLY DEFERRED DEFERRABLE clause at the end). But that would be a major pain if you delete data from either table with any sort of frequency. You'll also tend to have problems inserting new data if the new A row wants to reference the new B row you're creating.
I was unable to add INITIALLY DEFERRED because the databases (as well as the underlying Hibernate scripts) already exist. For new systems, this would have been an option, however, there are many tools (of which I only know several) which rely on the Database in its current form and I was too afraid of any unintended side-effects by adding this parameter to 700 tables.
Therefore, I used the following solution:
alter table TableA MODIFY CONSTRAINT FKA1 DISABLE;
alter table TableB MODIFY CONSTRAINT FKB1 DISABLE;
delete from TableA where id = 1;
delete from TableB where id = 2;
alter table TableA MODIFY CONSTRAINT FKA1 ENABLE;
alter table TableB MODIFY CONSTRAINT FKB1 ENABLE;
I create a table in Oracle 11g with the default value for one of the columns. Syntax is:
create table xyz(emp number,ename varchar2(100),salary number default 0);
This created successfully. For some reasons I need to create another table with same old table structure and data. So I created a new table with name abc as
create table abc as select * from xyz.
Here "abc" created successfully with same structure and data as old table xyz. But for the column "salary" in old table "xyz" default value was set to "0". But in the newly created table "abc" the default value is not set.
This is all in Oracle 11g. Please tell me the reason why the default value was not set and how we can set this using select statement.
You can specify the constraints and defaults in a CREATE TABLE AS SELECT, but the syntax is as follows
create table t1 (id number default 1 not null);
insert into t1 (id) values (2);
create table t2 (id default 1 not null)
as select * from t1;
That is, it won't inherit the constraints from the source table/select. Only the data type (length/precision/scale) is determined by the select.
The reason is that CTAS (Create table as select) does not copy any metadata from the source to the target table, namely
no primary key
no foreign keys
no grants
no indexes
...
To achieve what you want, I'd either
use dbms_metadata.get_ddl to get the complete table structure, replace the table name with the new name, execute this statement, and do an INSERT afterward to copy the data
or keep using CTAS, extract the not null constraints for the source table from user_constraints and add them to the target table afterwards
You will need to alter table abc modify (salary default 0);
new table inherits only "not null" constraint and no other constraint.
Thus you can alter the table after creating it with "create table as" command
or you can define all constraint that you need by following the
create table t1 (id number default 1 not null);
insert into t1 (id) values (2);
create table t2 as select * from t1;
This will create table t2 with not null constraint.
But for some other constraint except "not null" you should use the following syntax
create table t1 (id number default 1 unique);
insert into t1 (id) values (2);
create table t2 (id default 1 unique)
as select * from t1;