I am working on a legacy oracle database system (10g) and I do not have detailed schema information. I need to find out if deleting a particular record in a table will cause cascading deletes in other tables. I have checked for triggers. But, I am not sure about cascading due to referential constraints. Is there a simple way to identify this?
Assuming you know (or can determine) the foreign key constraint(s) involved, you can look at the DELETE_RULE column from DBA_CONSTRAINTS
SELECT constraint_name, delete_rule
FROM dba_constraints
WHERE r_constraint_name = <<name of the primary key constraint>>
AND r_owner = <<owner of the primary key constraint>>
AND delete_rule = 'CASCADE'
will show you all the foreign key constraints that refer to a particular primary key constraint and will cascade the deletes. If you care about constraints that will do a SET NULL when the parent row is deleted, you could look for rows where the delete_rule was SET NULL as well.
Note that if you do not have privileges on the DBA_CONSTRAINTS table, you can use ALL_CONSTRAINTS instead assuming that you're really only concerned with tables that you have SELECT privileges on.
Related
I want to know if there is some specific way to obtain a table-level check constraint in Oracle and in PostgreSQL.
I can obtain all the check constraints in a table, but I want to obtain only this specific check constraint, I don't know if there is any specific query.
Thanks!
In PostgreSQL there is a System Catalog pg_constraint.
The catalog pg_constraint stores check, primary key, unique, foreign
key, and exclusion constraints on tables. (Column constraints are not
treated specially. Every column constraint is equivalent to some table
constraint.) Not-null constraints are represented in the pg_attribute
catalog, not here.
User-defined constraint triggers (created with CREATE CONSTRAINT
TRIGGER) also give rise to an entry in this table.
Check constraints on domains are stored here, too.
SELECT
*
FROM
pg_constraint
WHERE
contype = 'c' AND -- check constraint
conrelid != 0 AND -- table constraint
conname = 'my_check';
The contype column contains the constraint type, c is for check constraint.
The conrelid column contains the oid of the table this constraint is on, 0 if not a table constraint.
For Oracle basic view is ALL_CONSTRAINTS
Query, to obtain specific constraint in specific table:
SELECT *
FROM all_constraints
WHERE constraint_name LIKE upper('%&your_costraint%')
AND table_name LIKE upper('%&your_table%');
Initial situation:
A table PARENT_TABLE with a primary key on its column PK_COL.
A table CHILD_TABLE1 with a foreign key on PARENT_TABLE(PK_COL).
I insert a line into CHILD_TABLE1 in a transaction and do not commit.
Then I try to create a table CHILD_TABLE2 symmetrical to CHILD_TABLE1 in another session.
But an ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired is raised when I create the foreign key, because of the ongoing insertion in CHILD_TABLE1.
I don't understand why Oracle is preventing the foreign key creation: there is no modification performed on PARENT_TABLE.
Please help.
To reproduce under sqlplus:
set autocommit off
create table PARENT_TABLE(PK_COL varchar(10));
alter table PARENT_TABLE add constraint PK_CONSTRAINT primary key (PK_COL);
insert into PARENT_TABLE values ('foo');
commit;
create table CHILD_TABLE1(CHILD_PK_COL varchar(10), FK_COL varchar(10));
alter table CHILD_TABLE1 add constraint CHILD_TABLE1_CONSTRAINT foreign key (FK_COL) references PARENT_TABLE(PK_COL);
create index CHILD_TABLE1_INDEX on CHILD_TABLE1(FK_COL);
insert into CHILD_TABLE1 values ('bar', 'foo');
In another console:
alter session set ddl_lock_timeout=10;
create table CHILD_TABLE2(CHILD_PK_COL varchar(10), FK_COL varchar(10));
alter table CHILD_TABLE2 add constraint CHILD_TABLE2_CONSTRAINT foreign key (FK_COL) references PARENT_TABLE(PK_COL);
Funny: with NOVALIDATE in CHILD_TABLE2_CONSTRAINT creation, the execution is hanging...
You are not modifying something in the parent table. But you're
actually, trying to refer its primary key in your child table. Before
establishing a relationship or any DDL with table, it has to be free
of locks.
So, before creating this constraint, Oracle do check for existing locks over the referred table(PARENT_TABLE). A lock over a table(Table Level Lock,in this context) is actually for a reason to adhere to the ACID properties.
One best example to understand its importance is ON DELETE CASCADE which means if a record in the parent table is deleted, then the corresponding records in the child table will automatically be deleted.
So, when there's a uncommitted insert/update/delete over the child table referring a parent table. No other referential constraint can be created to the parent. Just to avoid a deadlock or chaos.
To be more crisp, when you have an uncommitted insert in your child table.
There's a lock over your parent table as well. So all other further DDLs referring it will be made wait.
You can use this query to check the same.
SELECT c.owner,
c.object_name,
c.object_type,
b.sid,
b.serial#,
b.status,
b.osuser,
b.machine
FROM v$locked_object a ,
v$session b,
dba_objects c
WHERE b.sid = a.session_id
AND a.object_id = c.object_id;
I added the LOCKED_MODE explanation in you query:
DECODE(a.LOCKED_MODE, 0,'NONE', 1,'NULL', 2,'ROW SHARE (RS/SS)', 3,'ROW EXCLUSIVE (RX/SX)', 4,'SHARE (S)', 5,'SHARE ROW EXCLUSIVE (SRX/SSX)', 6,'EXCLUSIVE (X)', NULL) LOCK_MODE.
Here is the result:
OBJECT_NAME OBJECT_TYPE LOCK_MODE SID SERIAL# STATUS
------------------------------ ------------------- ----------------------------- ---------- ---------- --------
PARENT_TABLE TABLE ROW EXCLUSIVE (RX/SX) 71 8694 INACTIVE
CHILD_TABLE1 TABLE ROW EXCLUSIVE (RX/SX) 71 8694 INACTIVE
RX/SX is a table lock so it prevents any DDL operation (That seems to be said in the doc). This lock is used on both parent and child. I suppose that the lock is added on parent to at least prevent it from being deleted so we would lost the pending update on the child table.
That said, I still have no solution. Suppose that the parent table is a manufacturer. There is a child car table and we are inserting plenty of new cars in that table on the fly. There is a foreign key from car to manufacturer. Now there is a new product that we want to manage: "bicycles". So we want to create a bicycle table similar to car. But we cannot create the table as we are performing insertions in car. Seems a very simple use case... How to support it?
=====
Edit:
There might be no solution. Here is a guy with the same issue.
I want to ask a very basic question here.
We may/may not name a constraint while creating a table or after creating the table.
Suppose I chose not to name the foreign key constraint.
The table is having no records.
Can I delete the foreign key name without naming it.
I know how to get name of foreign key and then delete using it like
alter table my_table drop constraint fk_name;
but I want to delete/drop the foreign key constraint without mentioning its name.
Is there anyway to do it?
but i want to delete/drop the foreign key constraint without mentioning its name.
That's not possible. The dropping a foreign key constraint requires a name. However you can find out the system generated name:
select constraint_name
from user_constraints
where table_name = 'MY_TABLE'
and constraint_type = 'R';
Will show you all foreign keys defined on the table MY_TABLE. Using that statement you can even generate the necessary DDL statement:
select 'alter table "'||table_name||'" drop constraint "'||constraint_name||'";'
from user_constraints
where table_name = 'MY_TABLE'
and constraint_type = 'R';
Save the output of that select into a file and you have the statement(s) to drop all foreign keys from that table.
I have a oracle query as -
occupation varchar2(50) CHECK(occupation IN ('student','govt_service','private','business')));
now i need to remove the check constraint so i use the following query-
ALTER TABLE registration drop constraint occupation;
but since i haven't defined the constraint name it says invalid constraint name. Is there any way to delete the constraint ? I guess i can alter the table and add the name of the constraint, then delete it but is there any other way ?
run this query:
select * from all_constraints where table_name = 'REGISTRATION';
And you'll find the constraint name.
EDIT: I also recommend you to have a table Occupations and replace the current constraint with a foreign key. (If you are already want to do this, pls apologize me ). Further, normalising, the Occupations may have IDs and and the foreign should be defined on these ids.
Try querying USER_CONSTRAINTS table for CONSTRAINT_NAME, it must have generated a system name for the constraint you have created.
select * from USER_CONSTRAINTS
where owner='<your_schema>' and CONSTRAINT_TYPE='C';
I have a database which has a NOT NULL constraint on a field, and I want to remove this constraint. The complicating factor is that this constraint has a system-defined name, and that constraint's name differs between the production server, integration server, and the various developer databases. Our current process is to check in change scripts, and an automated task executes the appropriate queries through sqlplus against the target database, so I'd prefer a solution that could just be sent straight into sqlplus.
On my own database, the SQL to drop this would be:
alter table MYTABLE drop constraint SYS_C0044566
I can see the constraint when I query the all_constraints view:
select * from all_constraints where table_name = 'MYTABLE'
but I am not sure how to work with the SEARCH_CONDITION's LONG data type or how best to dynamically delete the looked-up constraint even after I know its name.
So, how can I create a change script that can drop this constraint based on what it is, rather than what its name is?
EDIT:
#Allan's answer is a good one, but I am concerned (in my lack of Oracle expertise) that it may not be universally true that any constraint that might have a system-generated name will have associated with it a way to remove the constraint without having to know its name. Is it true that there will always be a way to avoid having to know a system-named constraint's name when logically dropping that constraint?
alter table MYTABLE modify (MYCOLUMN null);
In Oracle, not null constraints are created automatically when not null is specified for a column. Likewise, they are dropped automatically when the column is changed to allow nulls.
Clarifying the revised question: This solution only applies to constraints created for "not null" columns. If you specify "Primary Key" or a check constraint in the column definition without naming it, you'll end up with a system-generated name for the constraint (and the index, for the primary key). In those cases, you'd need to know the name to drop it. The best advice there is to avoid the scenario by making sure you specify a name for all constraints other than "not null". If you find yourself in the situation where you need to drop one of these constraints generically, you'll probably need to resort to PL/SQL and the data-definition tables.
Try:
alter table <your table> modify <column name> null;
Just remember, if the field you want to make nullable is part of a primary key, you can't.
Primary Keys cannot have null fields.
To discover any constraints used, use the code below:
-- Set the long data type for display purposes to 500000.
SET LONG 500000
-- Define a session scope variable.
VARIABLE output CLOB
-- Query the table definition through the <code>DBMS_METADATA</code> package.
SELECT dbms_metadata.get_ddl('TABLE','[Table Described]') INTO :output FROM dual;
This essentially shows a create statement for how the referenced table is made. By knowing how the table is created, you can see all of the table constraints.
Answer taken from Michael McLaughlin's blog: http://michaelmclaughlin.info/db1/lesson-5-querying-data/lab-5-querying-data/ From his Database Design I class.
I was facing the same problem trying to get around a custom check constraint that I needed to updated to allow different values. Problem is that ALL_CONSTRAINTS does't have a way to tell which column the constraint(s) are applied to. The way I managed to do it is by querying ALL_CONS_COLUMNS instead, then dropping each of the constraints by their name and recreate it.
select constraint_name
from all_cons_columns
where table_name = [TABLE_NAME]
and column_name = [COLUMN_NAME];
Something like that happened to me when I made copies of structures to temporary tables, so I removed the not null.
DECLARE
CURSOR cur_temp_not_null IS
SELECT table_name, constraint_name FROM all_constraints WHERE table_name LIKE 'TEMP_%' AND owner='myUSUARIO';
V_sql VARCHAR2(200);
BEGIN
FOR c_not_null IN cur_temp_not_null
LOOP
v_sql :='ALTER TABLE ' || c_not_null.table_name || ' DROP CONSTRAINT '|| c_not_null.constraint_name;
EXECUTE IMMEDIATE v_sql;
END LOOP;
END;
If constraint on column STATUS was created without a name during creating a table, Oracle will assign a random name for it. Unfortunately, we cannot modify the constraint directly.
Steps involved of dropping unnamed constraint linked to column STATUS
Duplicate STATUS field into a new field STATUS2
Define CHECK constraints on STATUS2
Migrate data from STATUS into STATUS2
Drop STATUS column
Rename STATUS2 to STATUS
ALTER TABLE MY_TABLE ADD STATUS2 NVARCHAR2(10) DEFAULT 'OPEN';
ALTER TABLE MY_TABLE ADD CONSTRAINT MY_TABLE_CHECK_STATUS CHECK (STATUS2 IN ('OPEN', 'CLOSED'));
UPDATE MY_TABLE SET STATUS2 = STATUS;
ALTER TABLE MY_TABLE DROP COLUMN STATUS;
ALTER TABLE MY_TABLE RENAME COLUMN STATUS2 TO STATUS;