In Firebird I want to generate the scripts for adding all the constraints in a database and also I want to generate the script for dropping all the foreign key constraints.
How do I do this?
To generate a script which in turns drop all the foreign keys, use the following script in any firebird >= 2.0 (maybe it works on pre 2.0, just can't remember if data dictionary changed in involved system table):
--generate a script which drops all foreign keys
--by jachguate http://jachguate.wordpress.com
-- http://stackoverflow.com/users/255257/jachguate
select 'alter table '||c.rdb$relation_name||' drop constraint '||c.rdb$constraint_name||';' script_lines
from rdb$relation_constraints c
where c.rdb$constraint_type = 'FOREIGN KEY';
Edit
To generate a script to re-create all the foreign keys, this script will do the trick (for firebird >= 2.0). Remember to run this before actually deleting the foreign keys.
select 'alter table '||trim(c.rdb$relation_name)
||' add constraint '||trim(c.rdb$constraint_name)
||' foreign key ('
||(select list(trim(imast.rdb$field_name)) from rdb$index_segments imast where rdb$index_name = c.rdb$index_name)
||') references '||trim(uqc.rdb$relation_name)
||' ('
||(select list(trim(idet.rdb$field_name)) from rdb$index_segments idet where rdb$index_name = uqc.rdb$index_name)
||');'
from rdb$relation_constraints c
inner join rdb$ref_constraints rc
on rc.rdb$constraint_name = c.rdb$constraint_name
inner join rdb$relation_constraints uqc
on uqc.rdb$constraint_name = rc.rdb$const_name_uq;
Best regards.
Related
I am trying to add a new column to all tables in db which is a foreign key to one of the table. Ideally I should add the column to all tables instead of the table that the foreign key reference to.
How do I combine these two SQL statements to only one statement?
// Get all tables except the foreign key reference to
SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA="arthurMurray"
AND TABLE_TYPE="BASE TABLE"
AND TABLE_NAME!="Competitions";
// Add compeition_id to table as a foreign key to competitions table
ALTER TABLE t
ADD competition_id INTEGER,
ADD CONSTRAINT FOREIGN KEY(competition_id) REFERENCES Competitions(id);
Any help will be appreciate!
Please check this
EXEC sp_MSforeachtable '
if not exists (select * from sys.columns
where object_id = object_id(''?'')
and name = ''CreatedOn'')
begin
ALTER TABLE ? ADD CreatedOn datetime NOT NULL DEFAULT getdate();
end';
you ca use below query to generate your alter statement then you ca copy paste and execute below script.
SELECT
'ALTER TABLE ' + TABLE_NAME + 'ADD competition_id INTEGER, ADD CONSTRAINT FOREIGN KEY(competition_id) REFERENCES Competitions(id);'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='whatever_schema'
AND TABLE_TYPE='BASE TABLE'
AND TABLE_NAME!='Competitions';
I have got around 560 tables in my localhost with each and every single table having at least one primary key, foreign key references and for now all of them are empty.
I am starting to insert data into them but, as you have guessed - inserting into any one of these tables would be conflicted by on or the other key.
I am wondering if there is a way to figure out which table has got the highest foreign key references so that I can start inserting into it first. If what I am thinking or my approach sounds completely wrong, please suggest a better way.
I am using SQL Server 2012 and SSMS.
Try this:
SELECT Count(Object_name(parent_object_id)) AS cnt,
Object_name(parent_object_id) AS table_name
FROM sys.objects
WHERE type = 'f'
GROUP BY Object_name(parent_object_id)
ORDER BY cnt DESC
You can use the sys tables, this will get all the foreign keys:
SELECT tables.name as TableName, foreign_keys.name AS ForeignKeyName
FROM sys.foreign_keys
JOIN sys.tables
ON tables.object_id = foreign_keys.parent_object_id
With a slight modification you can get the count of foreign keys per table:
SELECT tables.name as TableName, COUNT(*) AS FKCount
FROM sys.foreign_keys
JOIN sys.tables
ON tables.object_id = foreign_keys.parent_object_id
GROUP BY tables.name
However, your task seems slightly different. My suggestion would be to disable all the keys, do your data transfer, then re-enable the keys:
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL"
--Do your data copy here
EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL"
Note that the re-enabling of keys here is forcing a check on the constraint, this is important otherwise SQL will not trust the foreign key and indexes/performance could be affected.
I'm pretty new to SQL, so it sould be rather easy to answer my questions.
Here is what I want to do:
Deactivate constraints:
Deactivate constraints in the database:
begin
for cur in (select fk.owner, fk.constraint_name , fk.table_name
from all_constraints fk, all_constraints pk
where fk.CONSTRAINT_TYPE = 'R' and
pk.owner = 'USER1' and
fk.R_CONSTRAINT_NAME = pk.CONSTRAINT_NAME ) loop
execute immediate 'ALTER TABLE '||cur.owner||'.'||cur.table_name||' MODIFY CONSTRAINT '||cur.constraint_name||' DISABLE';
end loop;
end;
Delete from tables:
delete from USER_TEST.Table1;
delete from USER_TEST.Table2;
delete from USER_TEST.Table3;
Reactivate Constraints:
begin
for cur in (select fk.owner, fk.constraint_name , fk.table_name
from all_constraints fk, all_constraints pk
where fk.CONSTRAINT_TYPE = 'R' and
pk.owner = 'USER1' and
fk.R_CONSTRAINT_NAME = pk.CONSTRAINT_NAME ) loop
execute immediate 'ALTER TABLE '||cur.owner||'.'||cur.table_name||' MODIFY CONSTRAINT '||cur.constraint_name||' ENABLE NOVALIDATE';
end loop;
end;
Does anyone know how to combine these steps into one .sql script so I can run this on Oracle SQLDeveloper? Or maybe a more elegant way to perform the deletion from the tables?
I'd be very thankful
If it is just about deleting from tables which have foreign keys to each other, you can always delete in constraint order ("children first"). Then you won't have to mess with your constraints at all. Don't forget to commit at the end.
If it is about speed, then you may want to disable constraints and empty the tables via TRUNCATE rather then DELETE. You should however, not delete ALL constraints of the schema, but just the foreign keys of the affected tables which point to another affected table. This will prevent you from shooting into your foot. You can to this without looping, just disable the constraints explicitly. E
So the entire script should look like this
Alter Table User_test.Table1 Modify Constraint FK... Disable;
Alter Table User_test.Table2 Modify Constraint FK... Disable;
...
Trunacte Table user_test.Table1;
Trunacte Table user_test.Table2;
...
Alter Table User_test.Table1 Modify Constraint FK... Enable;
Alter Table User_test.Table2 Modify Constraint FK... Enable;
...
I got the problem is when I run following command in Oracle, I encounter the error.
Truncate table mytable;
Errors:
ORA-02266: unique/primary keys in table referenced by enabled foreign keys
I found that, this mytable has relationship with other tables. That's why Truncate command cannot proceed anymore. How to delete data from myTable with the SQL scripts using Truncate command?
You have to swap the TRUNCATE statement to DELETE statements, slower and logged but that's the way to do it when constraints are in place.
DELETE mytablename;
Either that or you can find the foreign keys that are referencing the table in question and disable them temporarily.
select 'ALTER TABLE '||TABLE_NAME||' DISABLE CONSTRAINT '||CONSTRAINT_NAME||';'
from user_constraints
where R_CONSTRAINT_NAME='<pk-of-table>';
Where pk-of-table is the name of the primary key of the table being truncated
Run the output of the above query. When this has been done, remember to enable them again, just change DISABLE CONSTRAINT into ENABLE CONSTRAINT
this page offers a very good solution ...
ORA-02266: unique/primary keys in table referenced by enabled foreign keys
I'm here copying from it the Solution:
Find the referenced ENABLED foreign key constraints and disable them.
truncate/delete from the table .
using any text editor .. just change disable to enable in the output you get from the query , then run it.
select 'alter table '||a.owner||'.'||a.table_name||' disable constraint '||a.constraint_name||';'
from all_constraints a, all_constraints b
where a.constraint_type = 'R' and a.status='ENABLED'
and a.r_constraint_name = b.constraint_name
and a.r_owner = b.owner
and b.table_name = upper('YOUR_TABLE');
The error message is telling you that there are other table(s) with a foreign key constraint referring to your table.
According to the Oracle docs
You cannot truncate the parent table
of an enabled foreign key constraint.
You must disable the constraint before
truncating the table.
The syntax for disabling a foreign key is:
ALTER TABLE table_name disable
CONSTRAINT constraint_name;
Issue:
Error “ORA-02266: unique/primary keys in table referenced by enabled foreign keys” when trying to truncate a table.
Error Message:
SQL> truncate table TABLE_NAME;
truncate table TABLE_NAME
*
ERROR at line 1:
ORA-02266: unique/primary keys in table referenced by enabled foreign keys
Solution:
-- Find the referenced foreign key constraints.
SQL> select 'alter table '||a.owner||'.'||a.table_name||' disable constraint '||a.constraint_name||';'
2 from all_constraints a, all_constraints b
3 where a.constraint_type = 'R'
4 and a.r_constraint_name = b.constraint_name
5 and a.r_owner = b.owner
6 and b.table_name = 'TABLE_NAME';
'ALTER TABLE'||A.OWNER||'.'||A.TABLE_NAME||'DISABLE CONSTRAINT'||A.CONSTRAINT_NAME||';'
---------------------------------------------------------------------------------------------------------
alter table SCHEMA_NAME.TABLE_NAME_ATTACHMENT disable constraint CONSTRAINT_NAME;
alter table SCHEMA_NAME.TABLE_NAME_LOCATION disable constraint CONSTRAINT_NAME;
-- Disable them
alter table SCHEMA_NAME.TABLE_NAME_ATTACHMENT disable constraint CONSTRAINT_NAME;
alter table SCHEMA_NAME.TABLE_NAME_LOCATION disable constraint CONSTRAINT_NAME;
-- Run the truncate
SQL> truncate table TABLE_NAME;
Table truncated.
-- Enable the foreign keys back
SQL> select 'alter table '||a.owner||'.'||a.table_name||' enable constraint '||a.constraint_name||';'
2 from all_constraints a, all_constraints b
3 where a.constraint_type = 'R'
4 and a.r_constraint_name = b.constraint_name
5 and a.r_owner = b.owner
6 and b.table_name = 'TABLE_NAME';
'ALTER TABLE'||A.OWNER||'.'||A.TABLE_NAME||'ENABLE CONSTRAINT'||A.CONSTRAINT_NAME||';'
--------------------------------------------------------------------------------
alter table SCHEMA_NAME.TABLE_NAME_ATTACHMENT enable constraint CONSTRAINT_NAME;
alter table SCHEMA_NAME.TABLE_NAME_LOCATION enable constraint CONSTRAINT_NAME;
-- Enable them
alter table SCHEMA_NAME.TABLE_NAME_ATTACHMENT enable constraint CONSTRAINT_NAME;
alter table SCHEMA_NAME.TABLE_NAME_LOCATION enable constraint CONSTRAINT_NAME;
Oracle 12c introduced a feature to truncate a table that is a parent of a referential integrity constraint having ON DELETE rule.
Instead of truncate table tablename; use:
TRUNCATE TABLE tablename CASCADE;
From Oracle truncate table documentation:
If you specify CASCADE, then Oracle Database truncates all child tables that reference table with an enabled ON DELETE CASCADE referential constraint. This is a recursive operation that will truncate all child tables, granchild tables, and so on, using the specified options.
A typical approach to delete many rows with many constraints is as follows:
create mytable_new with all the columns but without constrains (or create constraints disabled);
copy whatever data you need from mytable to mytable_new.
enable constraints on mytable_new to see that everything is ok.
alter any constraints that reference mytable to reference mytable_new instead and see that everything is ok.
drop table mytable.
alter table mytable_new rename to mytable.
It's far faster than deleting a million records with many slow constraints.
I had the similar issue and I sorted it out by the following scripts.
begin
for i in (select constraint_name, table_name from user_constraints a where a.owner='OWNER' and a.table_name not in
(select b.table_name from user_constraints b where b.table_name like '%BIN%')
and a.constraint_type not in 'P')
LOOP
execute immediate 'alter table '||i.table_name||' disable constraint '||i.constraint_name||'';
end loop;
end;
/
truncate table TABLE_1;
truncate table TABLE_2;
begin
for i in (select constraint_name, table_name from user_constraints a where a.owner='OWNER' and a.table_name not in
(select b.table_name from user_constraints b where b.table_name like '%BIN%')
and a.constraint_type not in 'P')
LOOP
execute immediate 'alter table '||i.table_name||' enable constraint '||i.constraint_name||'';
end loop;
end;
/
This script will first disable all the Constraints. Truncates the data in the tables and then enable the contraints.
Hope it helps.
cheers..
TRUNCATE TABLE TEST2 DROP ALL STORAGE;
This statement Actually works when there is an foreign key constraint applied on a .table
As mentioned by the error message, you cannot truncate a table that is referenced by enabled foreign keys. If you really want to use the truncate DDL command, disable the foreign key constraint first, run the truncate command, and enable it back.
Reference: Difference between TRUNCATE, DELETE and DROP commands
I have a foreign key constraint in my table, I want to add ON DELETE CASCADE to it.
I have tried this:
alter table child_table_name
modify constraint fk_name
foreign key (child_column_name)
references parent_table_name (parent_column_name) on delete cascade;
Doesn't work.
EDIT:
Foreign key already exists, there are data in foreign key column.
The error message I get after executing the statement:
ORA-02275: such a referential constraint already exists in the table
You can not add ON DELETE CASCADE to an already existing constraint. You will have to drop and re-create the constraint. The documentation shows that the MODIFY CONSTRAINT clause can only modify the state of a constraint (i-e: ENABLED/DISABLED...).
First drop your foreign key and try your above command, put add constraint instead of modify constraint.
Now this is the command:
ALTER TABLE child_table_name
ADD CONSTRAINT fk_name
FOREIGN KEY (child_column_name)
REFERENCES parent_table_name(parent_column_name)
ON DELETE CASCADE;
As explained before:
ALTER TABLE TABLENAME
drop CONSTRAINT FK_CONSTRAINTNAME;
ALTER TABLE TABLENAME
ADD CONSTRAINT FK_CONSTRAINTNAME
FOREIGN KEY (FId)
REFERENCES OTHERTABLE
(Id)
ON DELETE CASCADE ON UPDATE NO ACTION;
As you can see those have to be separated commands, first dropping then adding.
Answer for MYSQL USERS:
ALTER TABLE ChildTableName
DROP FOREIGN KEY `fk_table`;
ALTER TABLE ChildTableName
ADD CONSTRAINT `fk_t1_t2_tt`
FOREIGN KEY (`parentTable`)
REFERENCES parentTable (`columnName`)
ON DELETE CASCADE
ON UPDATE CASCADE;
This PL*SQL will write to DBMS_OUTPUT a script that will drop each constraint that does not have delete cascade and recreate it with delete cascade.
NOTE: running the output of this script is AT YOUR OWN RISK. Best to read over the resulting script and edit it before executing it.
DECLARE
CURSOR consCols (theCons VARCHAR2, theOwner VARCHAR2) IS
select * from user_cons_columns
where constraint_name = theCons and owner = theOwner
order by position;
firstCol BOOLEAN := TRUE;
begin
-- For each constraint
FOR cons IN (select * from user_constraints
where delete_rule = 'NO ACTION'
and constraint_name not like '%MODIFIED_BY_FK' -- these constraints we do not want delete cascade
and constraint_name not like '%CREATED_BY_FK'
order by table_name)
LOOP
-- Drop the constraint
DBMS_OUTPUT.PUT_LINE('ALTER TABLE ' || cons.OWNER || '.' || cons.TABLE_NAME || ' DROP CONSTRAINT ' || cons.CONSTRAINT_NAME || ';');
-- Re-create the constraint
DBMS_OUTPUT.PUT('ALTER TABLE ' || cons.OWNER || '.' || cons.TABLE_NAME || ' ADD CONSTRAINT ' || cons.CONSTRAINT_NAME
|| ' FOREIGN KEY (');
firstCol := TRUE;
-- For each referencing column
FOR consCol IN consCols(cons.CONSTRAINT_NAME, cons.OWNER)
LOOP
IF(firstCol) THEN
firstCol := FALSE;
ELSE
DBMS_OUTPUT.PUT(',');
END IF;
DBMS_OUTPUT.PUT(consCol.COLUMN_NAME);
END LOOP;
DBMS_OUTPUT.PUT(') REFERENCES ');
firstCol := TRUE;
-- For each referenced column
FOR consCol IN consCols(cons.R_CONSTRAINT_NAME, cons.R_OWNER)
LOOP
IF(firstCol) THEN
DBMS_OUTPUT.PUT(consCol.OWNER);
DBMS_OUTPUT.PUT('.');
DBMS_OUTPUT.PUT(consCol.TABLE_NAME); -- This seems a bit of a kluge.
DBMS_OUTPUT.PUT(' (');
firstCol := FALSE;
ELSE
DBMS_OUTPUT.PUT(',');
END IF;
DBMS_OUTPUT.PUT(consCol.COLUMN_NAME);
END LOOP;
DBMS_OUTPUT.PUT_LINE(') ON DELETE CASCADE ENABLE VALIDATE;');
END LOOP;
end;
Here is an handy solution!
I'm using SQL Server 2008 R2.
As you want to modify the FK constraint by adding ON DELETE/UPDATE CASCADE, follow these steps:
NUMBER 1:
Right click on the constraint and click to Modify
NUMBER 2:
Choose your constraint on the left side (if there are more than one). Then on the right side, collapse "INSERT And UPDATE Specification" point and specify the actions on Delete Rule or Update Rule row to suit your need. After that, close the dialog box.
NUMBER 3:
The final step is to save theses modifications (of course!)
PS: It's saved me from a bunch of work as I want to modify a primary key referenced in another table.
For anyone using MySQL:
If you head into your PHPMYADMIN webpage and navigate to the table that has the foreign key you want to update, all you have to do is click the Relational view located in the Structure tab and change the On delete select menu option to Cascade.
Image shown below:
If you want to change a foreign key without dropping it you can do:
ALTER TABLE child_table_name WITH CHECK ADD FOREIGN KEY(child_column_name)
REFERENCES parent_table_name (parent_column_name) ON DELETE CASCADE
for postgresql
BEGIN TRANSACTION ;
ALTER TABLE bank_accounts
DROP CONSTRAINT bank_accounts_company_id_fkey;
ALTER TABLE bank_accounts
ADD CONSTRAINT bank_accounts_company_id_fkey FOREIGN KEY (company_id)
REFERENCES companies (id)
ON DELETE CASCADE;
END;
ALTER TABLE `tbl_celebrity_rows` ADD CONSTRAINT `tbl_celebrity_rows_ibfk_1` FOREIGN KEY (`celebrity_id`)
REFERENCES `tbl_celebrities`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
MySQL workbench img
Right click at the table you want to alter and click alter table, then click Foreign Keys. You can see Foreign Keys Options on the right side and just select cascade and click apply!