I am not clear about what happens when a "foreign key constraint" is deleted specifying the option CASCADE.
For instance, consider this command
ALTER TABLE table1 DROP CONSTRAINT foreignKeyToTable2 CASCADE.
What the option CASCADE is supposed to do in this case? What would happen if I omitted it? And if I wrote RESTRICT instead of CASCADE?
Note: this example of query is excerpted from "Ramez Elmasri, Shamkant B. Navathe - Fundamentals of database systems, end of chapter 5".
The cascade option to drop a constraint is only needed when dropping primary keys, not when dropping a foreign key.
Consider this example in Postgres:
create table t1 (id integer, constraint pk_one primary key (id));
create table t2 (id integer primary key, id1 integer references t1);
When you try to run:
alter table t1 drop constraint pk_one;
You get:
ERROR: cannot drop constraint pk_one on table t1 because other objects depend on it
Detail: constraint t2_id1_fkey on table t2 depends on index pk_one
Hint: Use DROP ... CASCADE to drop the dependent objects too.
If you run:
alter table t1 drop constraint pk_one cascade;
you get:
NOTICE: drop cascades to constraint t2_id1_fkey on table t2
Telling you that the foreign key that needed the primary key was dropped as well.
Note that not all DBMS support a cascading drop. Postgres and Oracle do.
MySQL, SQL Server or Firebird do not. You need to drop the foreign keys manually in those DBMS.
Related
I created a table but forgot to select primary and foreign key to join the table.
How can I fix this process?
You can use the ALTER TABLE Statement
ALTER TABLE table_name
ADD CONSTRAINT MyPrimaryKey
PRIMARY KEY (column1, column2...);
ALTER TABLE table_name
ADD CONSTRAINT MyForeignKey
FOREIGN KEY (column1) REFERENCES Table(column);
I have the following table
CREATE TABLE steps (
hash_id text UNIQUE PRIMARY KEY,
depth integer
);
-- Indices -------------------------------------------------------
CREATE UNIQUE INDEX steps_hash_id_key ON steps(hash_id text_ops);
CREATE UNIQUE INDEX steps_pkey ON steps(hash_id text_ops);
But I'd like to remove the redundant UNIQUE index because PRIMARY KEY is already unique.
I've also many other tables linked to the hash_id of my steps table with foreign keys.
When I try to remove my UNIQUE index like this:
ALTER TABLE steps DROP CONSTRAINT steps_hash_id_key;
I get
ERROR: cannot drop constraint steps_hash_id_key on table steps because other objects depend on it
DETAIL: constraint steps_routes_step_hash_id_fkey on table steps_routes depends on index steps_hash_id_key
constraint steps_likes_dislikes_step_hash_id_fkey on table steps_likes_dislikes depends on index steps_hash_id_key
HINT: Use DROP ... CASCADE to drop the dependent objects too.
The matter is that I don't want to cascade delete anything, I'd just like to remove this duplicated unique index. Is it possible ?
Thanks to the discussion in comments (#Gordon Linoff) here's a way to fix this issue:
Drop foreign keys
Drop Primary Keys and Unique Keys
Recreate Primary Key only
Recreate Foreign Keys
ALTER TABLE steps_routes DROP CONSTRAINT steps_routes_step_hash_id_fkey;
ALTER TABLE steps_likes_dislikes DROP CONSTRAINT steps_likes_dislikes_step_hash_id_fkey;
ALTER TABLE steps DROP CONSTRAINT steps_pkey;
ALTER TABLE steps DROP CONSTRAINT steps_hash_id_key;
ALTER TABLE steps ADD PRIMARY KEY (hash_id);
ALTER TABLE steps_routes ADD FOREIGN KEY (step_hash_id) REFERENCES steps(hash_id) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE steps_likes_dislikes ADD FOREIGN KEY (step_hash_id) REFERENCES steps(hash_id) ON DELETE CASCADE ON UPDATE CASCADE;
I'm using Teradata 16.20.05.01 to run the following script:
create table t1(v int not null);
create table t2(w int null);
alter table t1 add constraint pk primary key (v);
alter table t2 add constraint t2_fk foreign key (w) references t1 (v);
After adding the foreign key, I suddenly get one excess table in my schema:
select TableName, RequestText
from "DBC".Tables
where DatabaseName = 'test'
and (TableName like 't1%' or TableName like 't2%')
Output:
TableName |RequestText |
----------|----------------------------------------------------------------------|
t1 |alter table t1 add constraint pk primary key (v) |
t2 |create table t2(w int null) |
T2_0 |alter table t2 add constraint t2_fk foreign key (w) references t1 (v) |
This is especially annoying when re-creating that foreign key:
alter table t2 drop constraint t2_fk;
alter table t2 add constraint t2_fk foreign key (w) references t1 (v);
Which isn't possible because of:
SQL Error [5303] [HY000]: [Teradata Database] [TeraJDBC 15.00.00.33] [Error 5303] [SQLState HY000] Error table 'TEST.t2_0' already exists.
Workaround:
The problem does not appear when using inline constraint definitions
create table t1(v int not null, constraint pk primary key (v));
create table t2(w int null, constraint t2_fk foreign key (w) references t1 (v));
Is this a known issue? Is there a reliable workaround?
This is documented behaviour, when you add a Foreign Key to an existing table there's an error table created and all all rows violating the constraint are copied into it. And it's not dropped automatically after the ALTER.
The workaround is simple: Don't use Standard Foreign Keys, you will hardly find any site using it. Switch to Batch FKs, i.e. REFERENCES WITH CHECK OPTION, which applies the check on a request level (not row by row), or to a Soft/Dummy FK, REFERENCES WITH NO CHECK OPTION, which simply defined the constraint without enforcing it (you must check for PK/FK violations in your load scripts anyway).
I have a weird problem where after setting nocheck on a foreign constraint and re-enabling it,
I am getting a same out-dated execution plan that was used with nocheck on.
Why would SQL server generate an execution plan as if foreign constraint FKBtoA is disabled even after adding the check again with following statement?
alter table B check constraint FKBtoA
[UPDATE1]
So far dropping foreign constraint and readding it worked.
alter table B drop constraint FKBtoA
alter table B add constraint FKBtoA foreign key (AID) references A(ID)
But for really big tables, this seems like an overkill - Is there a better way?
[ANSWER]
I had to add WITH CHECK in alter statement like following to get the old execution plan
alter table B WITH CHECK add constraint FKBtoA foreign key (AID) references A(ID)
Here is a full SQL statement
create table A ( ID int identity primary key )
create table B (
ID int identity primary key,
AID int not null constraint FKBtoA references A (ID)
)
select *
from B
where exists (select 1 from A where A.ID = B.AID)
alter table B nocheck constraint FKBtoA
GO
select *
from B
where exists (select 1 from A where A.ID = B.AID)
alter table B check constraint FKBtoA
GO
select *
from B
where exists (select 1 from A where A.ID = B.AID)
Here is the screenshot of execution plans per each SELECT statement
Before disabling foreign key constraint
After disabling foreign key constraint
After re-enabling foreign key constraint
Most likely your constraint is enabled but not trusted, so there can be orphan rows in your child table. Read this great post by Hugo Kornelis:Can you trust your constraints?
There doesn't seem to be any data in those tables, judging from both the scripts you posted and from the width of the connectors in the plan. Analyzing query plans on empty tables is largely irrelevant: at one single page read, the optimizer will almost certainly choose a full scan.
I assume you're doing this as some sort of experiment, in real world you should join those tables not use inner EXIST.
Personally I do not know, but I know how to rebuild statistics...
I'm trying to move a primary key constraint to a different column in oracle. I tried this:
ALTER TABLE MY_TABLE
DROP CONSTRAINT c_name;
ALTER TABLE MY_TABLE
ADD CONSTRAINT c_name PRIMARY KEY
(
"COLUMN_NAME"
) ENABLE;
This fails on the add constraint with an error saying the the constraint already exists even though i just dropped it. Any ideas why this is happening
If the original constraint was a primary key constraint, Oracle creates an index to enforce the constraint. This index has the same name as the constraint (C_NAME in your example). You need to drop the index separately from the constraint. So you will need to do a :
ALTER TABLE <table1> DROP CONSTRAINT C_NAME;
DROP INDEX C_NAME;
ALTER TABLE <table1> ADD CONSTRAINT C_NAME PRIMARY KEY
( COLUMN_2 ) ENABLE;
The safest way is to first add a unique index. Try this:
create unique index new_pk on <tabname> (column_2);
Then drop the old PK:
alter table <tabname> drop primary key drop index;
(Optional) Rename the index:
alter index new_pk rename to c_name;
And then add the PK again indicating the index to be used:
alter table <tabname> add constraint c_name
primary key (column_2) using index c_name;
I don't know if this is a similar problem but, in DB2, you have to actually commit following the alter table statement. Otherwise it's still hanging around.