Cannot truncate table because it is being referenced by a FOREIGN KEY constraint - sql-server

I get the following message even when the table that references it is empty: "Cannot truncate table 'dbo.Link' because it is being referenced by a FOREIGN KEY constraint" Doesn't seem to make much sense why this is occurring. Any suggestions?

In SQL Server a table referenced by a FK cannot currently be truncated even if all referencing tables are empty or the foreign keys are disabled.
You need to use DELETE (may require much more logging) or drop the relationship(s) prior to using TRUNCATE and recreate them afterwards or see the workarounds on this connect item for a way of achieving this using ALTER TABLE ... SWITCH

You cannot truncate a table which has an FK constraint on it. As workaround, you could:
1/ Drop the constraints
2/ Trunc the table
3/ Recreate the constraints.
Here it is the associated T-SQL script, supposing you have 2 tables called MyTable and MyReferencedTable:
-- Remove constraint
IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_MyReferencedTable_MyTable')
BEGIN
ALTER TABLE dbo.MyReferencedTable
DROP CONSTRAINT FK_MyReferencedTable_MyTable
END
-- Truncate table
TRUNCATE TABLE dbo.MyTable
-- Re-Add constraint
IF NOT EXISTS(SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_MyReferencedTable_MyTable')
BEGIN
ALTER TABLE dbo.MyReferencedTable
WITH CHECK ADD CONSTRAINT [FK_MyReferencedTable_MyTable] FOREIGN KEY(ListingKey)
REFERENCES dbo.MyTable (ListingKey)
END

Execute the following query to search any constraint:
use MyDatabase
select c.name as c_name, t.name as t_name
from sys.key_constraints c
join sys.tables t on t.object_id = c.parent_object_id
If any constraint found on your table, remove it.

If you are receiving this error and you need to truncate the table then alternative solution could be that you can drop and re-create the table along with primary/other_keys/indexes/triggers. Please make sure that you don't need to the data in that table.
This soulution is working like a charm for me and hardly took a minute to finish. I am doing it for masking purpose.

Not for SQL Server but MySQL only.
Instead of deleting or recreating the constraint, I prefer this simpler way.
Disable the constraint validation by executing the following query first :
SET FOREIGN_KEY_CHECKS=0;
Then truncate your tables
And finally, reactivate the constraint validation :
SET FOREIGN_KEY_CHECKS=1;
Thats a common solution when you migrate databases, so you don't have to worry about the order the tables are inserted in.

Related

Adding constraint conflicts with itself, even though it doesn't exist yet

I'm adding delete cascading to a Table. The Clone table has a column DeviceID that is a foreign key to the Device table's DeviceID column. So the SQL script drops the original FK constraint, and attempts to add the new one:
IF EXISTS
(
SELECT *
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_NAME = 'FK_Clone_Device'
)
BEGIN
ALTER TABLE Clone
DROP CONSTRAINT FK_Clone_Device
END
IF NOT EXISTS
(
SELECT *
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_NAME = 'FK_Clone_Device_Cascade'
)
BEGIN
ALTER TABLE Clone
ADD CONSTRAINT FK_Clone_Device_Cascade
FOREIGN KEY (DeviceID) REFERENCES Device(DeviceID) ON DELETE CASCADE
END
When I run this script, I get the following error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_Clone_Device_Cascade". The conflict occurred in database "DevelopmentDB", table "dbo.Device", column 'DeviceID'.
Maybe I'm misunderstanding the error message, but it sounds like it's conflicting with itself. I'm confused that it happened on the Device table though.
There is an index in the Clone table on DeviceID. Would that matter?
This is on SQL SERVER R2 (Azure)
Sounds like you currently have data in the table that would violate the FK you are trying to create. One way to test this is to add "WITH (NOCHECK)" to the ALTER TABLE statement and see if it lets you create the constraint.
If it does let you create the constraint with NOCHECK, you can either leave it that way and the constraint will only be used to test future inserts/updates, or you can investigate your data to fix the FK violations.
So your example would be:
ALTER TABLE Clone WITH NOCHECK
ADD CONSTRAINT FK_Clone_Device_Cascade
FOREIGN KEY (DeviceID) REFERENCES Device(DeviceID) ON DELETE CASCADE

Create a foreign key to system tables

I want to create table with to columns:
IdRole
IdProcedure
the idea is that IdProcedure is a FK to sys.objects.
When I create this query:
SELECT *
FROM sys.objects
WHERE type='p'
it works fine, but this one:
ALTER TABLE dbo.CORE_ProcedureXRole
ADD CONSTRAINT FK_SysProcedure
FOREIGN KEY (IdProcedure)
REFERENCES sys.objects(object_id)
tells me:
Foreign key 'FK_SysProcedure' references invalid table
'sys.objects'.
sys.objects isn't a table. It's a system view backed by data stored in proprietary SQL Server format. If you want to make sure that the stored name is correct, add a TRIGGER for update and insert to handle the checking.

How to remove a column from an existing table?

How to remove a column from an existing table?
I have a table MEN with Fname and Lname
I need to remove the Lname
How to do it?
ALTER TABLE MEN DROP COLUMN Lname
Generic:
ALTER TABLE table_name DROP COLUMN column_name;
In your case:
ALTER TABLE MEN DROP COLUMN Lname;
Your example is simple and doesn’t require any additional table changes but generally speaking this is not so trivial.
If this column is referenced by other tables then you need to figure out what to do with other tables/columns. One option is to remove foreign keys and keep referenced data in other tables.
Another option is to find all referencing columns and remove them as well if they are not needed any longer.
In such cases the real challenge is finding all foreign keys. You can do this by querying system tables or using third party tools such as ApexSQL Search (free) or Red Gate Dependency tracker (premium but more features). There a whole thread on foreign keys here
This is the correct answer:
ALTER TABLE MEN DROP COLUMN Lname
But... if a CONSTRAINT exists on the COLUMN, then you must DROP the CONSTRAINT first, then you will be able to DROP the COLUMN. In order to drop a CONSTRAINT, run:
ALTER TABLE MEN DROP CONSTRAINT {constraint_name_on_column_Lname}
In SQL Server 2016 you can use new DIE statements.
ALTER TABLE Table_name DROP COLUMN IF EXISTS Column_name
The above query is re-runnable it drops the column only if it exists in the table else it will not throw error.
Instead of using big IF wrappers to check the existence of column before dropping it you can just run the above DDL statement
The question is, can you only delete a column from an unexisting table ;-)
BEGIN TRANSACTION
IF exists (SELECT * FROM sys.columns c
INNER JOIN sys.objects t ON (c.[object_id] = t.[object_id])
WHERE t.[object_id] = OBJECT_ID(N'[dbo].[MyTable]')
AND c.[name] = 'ColumnName')
BEGIN TRY
ALTER TABLE [dbo].[MyTable] DROP COLUMN ColumnName
END TRY
BEGIN CATCH
print 'FAILED!'
END CATCH
ELSE
BEGIN
SELECT ERROR_NUMBER() AS ErrorNumber;
print 'NO TABLE OR COLUMN FOUND !'
END
COMMIT
The simple answer to this is to use this:
ALTER TABLE MEN DROP COLUMN Lname;
More than one column can be specified like this:
ALTER TABLE MEN DROP COLUMN Lname, secondcol, thirdcol;
From SQL Server 2016 it is also possible to only drop the column only if it exists. This stops you getting an error when the column doesn't exist which is something you probably don't care about.
ALTER TABLE MEN DROP COLUMN IF EXISTS Lname;
There are some prerequisites to dropping columns. The columns dropped can't be:
Used by an Index
Used by CHECK, FOREIGN KEY, UNIQUE, or PRIMARY KEY constraints
Associated with a DEFAULT
Bound to a rule
If any of the above are true you need to drop those associations first.
Also, it should be noted, that dropping a column does not reclaim the space from the hard disk until the table's clustered index is rebuilt. As such it is often a good idea to follow the above with a table rebuild command like this:
ALTER TABLE MEN REBUILD;
Finally as some have said this can be slow and will probably lock the table for the duration. It is possible to create a new table with the desired structure and then rename like this:
SELECT
Fname
-- Note LName the column not wanted is not selected
INTO
new_MEN
FROM
MEN;
EXEC sp_rename 'MEN', 'old_MEN';
EXEC sp_rename 'new_MEN', 'MEN';
DROP TABLE old_MEN;
But be warned there is a window for data loss of inserted rows here between the first select and the last rename command.
To add columns in existing table:
ALTER TABLE table_name
ADD
column_name DATATYPE NULL
To delete columns in existing table:
ALTER TABLE table_name
DROP COLUMN column_name
This can also be done through the SSMS GUI. The nice thing about this method is it warns you if there are any relationships on that column and can also automatically delete those as well.
Put table in Design view (right click on table) like so:
Right click on column in table's Design view and click "Delete
Column"
As I stated before, if there are any relationships that would also need to be deleted, it will ask you at this point if you would like to delete those as well. You will likely need to do so to delete the column.
If you are using C# and the Identity column is int, create a new instance of int without providing any value to it.It worked for me.
[identity_column] = new int()
Syntax:
ALTER TABLE TABLE_NAME DROP COLUMN COLUMN_NAME;
For Example:
alter table Employee drop column address;

Change primary key value in Oracle

Is there a way to change the value of a primary key which is referenced by another table as foreign key?
An easier alternative is to insert a new row and delete the old one. (Update any referencing rows in other tables before you do the delete)
There isn't an in-built UPDATE CASCADE if that's what you're after. You'd need to do something like disable any FK constraints; run UPDATE statements; re-enable the constraints.
Note that updating Primary Keys is (usually always) a bad idea.
You will need to disable the foreign key constraints before changing the primary key values, and then re-enable them afterwards.
If you actually want to implement "update cascade" functionality instead then see Tom Kyte's Update Cascade package
It is possible even without disabling constraints, in case if you would like only to swap keys (which is also a change's subset, so it might be still answer to your question). I wrote an example here: https://stackoverflow.com/a/26584576/1900739
update MY_TABLE t1
set t1.MY_KEY = (case t1.MY_KEY = 100 then 101 else 100 end)
where t1.MYKEY in (100, 101)
Yes, there is a way to do the cascading update in Oracle, even within a transaction (which does not hold true for the option of enabling/disabling constraints). However, you'll have to implement it yourself. It can be done via before/after-row-update triggers.
It is possible due to the fact that triggers are executed before any constraints are checked. (Well, at least in Oracle 11.2 it was true. Haven't checked against 12.1, but I honestly believe it hasn't changed.)
Anyway, as said before, updating primary keys is usually a bad idea.
The principe is to disable constrainsts, run your udates based on key, and reenable the constrainst. That for here is a script that run the disable script :
(Assuming all the constraints are enable at start)
Generate the script
SELECT 'alter table ' || uc.table_name|| ' disable constraint '|| uc.constraint_name|| ' ;'
FROM user_constraints uc inner join user_cons_columns ucc on uc.constraint_name = ucc.constraint_name where column_name = 'MYCOLUMN_USED_AS_FOREIGN_KEY' and constraint_type='R'
Copy/paste the generated script and run it
alter table MYTABLE1 disable constraint FK_MYTABLE1 ;
alter table MYTABLE2 disable constraint MYTABLE2 ;
alter table MYTABLE3 disable constraint FK3_MYTABLE3 ;
...
Then update your PK values :
update MYTABLE1 set MYFIELD= 'foo' where MYFIELD='bar';
update MYTABLE2 set MYFIELD= 'foo' where MYFIELD='bar';
update MYTABLE3 set MYFIELD= 'foo' where MYFIELD='bar';
commit;
Generate the enable constraints script :
SELECT 'alter table ' || uc.table_name|| ' enable constraint '|| uc.constraint_name|| ' ;'
FROM user_constraints uc inner join user_cons_columns ucc on uc.constraint_name = ucc.constraint_name where column_name = 'MYCOLUMN_USED_AS_FOREIGN_KEY' and constraint_type='R'
Another way you can do this is by changing the foreign key constraints so that the validation of the constraint is deferred until you commit - i.e. instead of Oracle validating the constraints statement-by-statement, it'll do it transaction-by-transaction.
Note you can't do this via the "alter table" statement, but you can drop and re-create the foreign key constraint to be deferrable, i.e:
alter table <table name> drop constraint <FK constraint name>;
alter table <table name> add constraint <FK constraint name> foreign key .... initially deferrable;
Once you've done that, just update the tables in whatever order you like, and commit - at which point, either:
All your FK constraints are satisfied, and everyone's happy; or
You've violated a FK constraint somewhere - you'll get an error and you'll have to fix up the data and commit, or rollback.
Note this feature is quite safe, as Oracle does not allow dirty reads so they'll only see the effects of your updates once you commit. So from the perspective of every other session, referential integrity appears to be preserved.
Also, this is a once-off change, so you don't need to go executing DDL each time you want to go updating the primary keys.

Deleting a SQL row ignoring all foreign keys and constraints

I have a row in a table. This row has an ID column referenced in a few other tables with millions of rows. The SQL statement to delete the row always times out. From my design, I know the row I wish to delete is never referenced any where else. Hence I would like SQL to ignore having to check all other tables for a foreign key reference to this row and delete the row immediately. Is there a quick way to do this in SQL 2008?
Perhaps something along the lines of:
DELETE FROM myTable where myTable.ID = 6850 IGNORE CONSTRAINTS
Or something along those lines.
You can set the constraints on that table / column to not check temporarily, then re-enable the constraints. General form would be:
ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName
Then re-enable all constraints with
ALTER TABLE TableName CHECK CONSTRAINT ConstraintName
I assume that this would be temporary though? You obviously wouldn't want to do this consistently.
Yes, simply run
DELETE FROM myTable where myTable.ID = 6850
AND LET ENGINE VERIFY THE CONSTRAINTS.
If you're trying to be 'clever' and disable constraints, you'll pay a huge price: enabling back the constraints has to verify every row instead of the one you just deleted. There are internal flags SQL keeps to know that a constraint is 'trusted' or not. You're 'optimization' would result in either changing these flags to 'false' (meaning SQL no longer trusts the constraints) or it has to re-verify them from scratch.
See Guidelines for Disabling Indexes and Constraints and Non-trusted constraints and performance.
Unless you did some solid measurements that demonstrated that the constraint verification of the DELETE operation are a performance bottleneck, let the engine do its work.
Do not under any circumstances disable the constraints. This is an extremely stupid practice. You cannot maintain data integrity if you do things like this. Data integrity is the first consideration of a database because without it, you have nothing.
The correct method is to delete from the child tables before trying to delete the parent record. You are probably timing out because you have set up cascading deltes which is another bad practice in a large database.
I know this is an old thread, but I landed here when my row deletes were blocked by foreign key constraints. In my case, my table design permitted "NULL" values in the constrained column. In the rows to be deleted, I changed the constrained column value to "NULL" (which does not violate the Foreign Key Constraint) and then deleted all the rows.
I wanted to delete all records from both tables because it was all test data. I used SSMS GUI to temporarily disable a FK constraint, then I ran a DELETE query on both tables, and finally I re-enabled the FK constraint.
To disable the FK constraint:
expand the database object [1]
expand the dependant table object [2]
expand the 'Keys' folder
right click on the foreign key
choose the 'Modify' option
change the 'Enforce Foreign Key Constraint' option to 'No'
close the 'Foreign Key Relationships' window
close the table designer tab
when prompted confirm save changes
run necessary delete queries
re-enable foreign key constraint the same way you just disabled it.
[1] in the 'Object Explorer' pane, can be accessed via the 'View' menu option, or key F8
[2] if you're not sure which table is the dependant one, you can check by right clicking the table in question and selecting the 'View Dependencies' option.
This is the way to disable foreign key checks in MySQL. Not relevant to OP's question since they use MS SQL Server, but google search results do turn this up so here's for reference:
SET FOREIGN_KEY_CHECKS = 0;
/ Run your script /
SET FOREIGN_KEY_CHECKS = 1;
See if this helps, This is for ignoring the foreign key checks.
But deleting disabling this is very bad practice.
On all tables with foreign keys pointing to this one, use:
ALTER TABLE MyOtherTable NOCHECK CONSTRAINT fk_name
You can disable all of the constaints on your database by the following line of code:
EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
and after the runing your update/delete command, you can enable it again as the following:
EXEC sp_MSforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
You could maybe disable and re-enable constraints:
http://sqlforums.windowsitpro.com/web/forum/messageview.aspx?catid=60&threadid=48410&enterthread=y
For the testing purpose only, I used the following command in MySQL to delete only one record from a table that has foreign key references.
SET FOREIGN_KEY_CHECKS = 0; -- Disabling foreign key checks before running the following query.
DELETE FROM table_name WHERE id = id_to_delete; -- Deleting a record from a table that has foreign key reference.
SET FOREIGN_KEY_CHECKS = 1; -- Enabling foreign key checks after running the above query.
Temporarily disable constraints on a table T-SQL, SQL Server
MSSQL
ALTER TABLE TableName NOCHECK CONSTRAINT ALL
ALTER TABLE TableName CHECK CONSTRAINT ALL
ALTER TABLE TableName NOCHECK CONSTRAINT FK_Table_RefTable
ALTER TABLE TableName CHECK CONSTRAINT FK_Table_RefTable
ref
DELETE FROM TableName
DBCC CHECKIDENT ('TableName', RESEED, 0)
MySql
SET FOREIGN_KEY_CHECKS = 0; -- Disable foreign key checking.
TRUNCATE TABLE [YOUR TABLE];
SET FOREIGN_KEY_CHECKS = 1;

Resources