How can i drop tables with constraints,
use my_db0
if exists(select* from sys.tables where name='Tbl1')
drop table Tbl1 --cascade constraints;
Create table Tbl1(
nameID int primary key
)
if exists (select* from sys.tables where name='Tbl2')
drop table Tbl2
Create table Tbl2(
lastNameID int primary key,
nameID int foreign key references Tbl1(nameID)
)
The table Tbl2 contains nameID as a foreign key , so you have to first wipe the the data in Tbl2 and then drop the Tbl1
if exists (select* from sys.tables where name='Tbl2')
drop table Tbl2
if exists(select* from sys.tables where name='Tbl1')
drop table Tbl1
In SQL Server 2016 you can use DROP IF EXISTS:
ALTER TABLE my_table
DROP CONSTRAINT IF EXISTS <name>
DROP TABLE IF EXISTS my_table
See http://blogs.msdn.com/b/sqlserverstorageengine/archive/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016.aspx
Jovan
You can use this query:
Select Query =
'If EXISTS (Select * FROM sys.foreign_keys Where '
+ ' object_id = OBJECT_ID(N''' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id)) + '.' + QUOTENAME(fk.name) + ''')'
+ ' And parent_object_id = OBJECT_ID(N''' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id)) + '.' + OBJECT_NAME(fk.parent_object_id) + ''')) ' +
'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id))
+ ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + '; '
, [Schema] = sh.name, [Table] = OBJECT_NAME(fk.parent_object_id), [Constraint] = ob.name
From sys.foreign_keys as fk
Inner Join sys.objects as ob on ob.object_id = fk.parent_object_id
Inner Join sys.schemas as sh on ob.schema_id = sh.schema_id
Where ob.name in ('xxx', 'yyy');
It will output:
Drop constraint query
Schema name
Table name
Constraint name
You can then dynamicaly execute the queries in the first column:
Exec sp_executesql #sql
Where #sql comes from the Query column. Once the constraints have been remove, you can drop the table.
Related
I have got the following code in t-SQL:
alter table Persons
drop primary key;
And the message:
Msg 156, Level 15, State 1, Line 10
Incorrect syntax near the keyword 'primary'.
I have checked different combinations of syntax and none have worked.
What is wrong here?
This is how a table has been created - it is just beggining of studying, so very simple one with only two constraints.
create table Persons(
PersonID int not null primary key,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
City varchar(255)
);
It's not DROP PRIMARY KEY it's DROP CONSTRAINT {Object Name}. For example:
CREATE TABLE dbo.YourTable (ID int NOT NULL);
GO
ALTER TABLE dbo.YourTable ADD CONSTRAINT PK_YourTable PRIMARY KEY CLUSTERED (ID);
GO
ALTER TABLE dbo.YourTable DROP CONSTRAINT PK_YourTable;
GO
DROP TABLE dbo.YourTable;
This is why it's so important to explicitly name your objects, as shown above, as you now don't know what the name of the CONSTRAINT is. You could, however, get the name with the following:
SELECT kc.[name]
FROM sys.key_constraints kc
JOIN sys.tables t ON kc.parent_object_id = t.object_id
JOIN sys.schemas s ON t.schema_id = t.schema_id
WHERE s.[name] = N'dbo'
AND t.[name] = N'YourTable'
AND kc.[type] = 'PK';
If you really didn't want to find out the name and then write the statement, you could use a dynamic statement:
DECLARE #SQL nvarchar(MAX);
SET #SQL = (SELECT N'ALTER TABLE ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N' DROP CONSTRAINT ' + QUOTENAME(kc.[name]) + N';'
FROM sys.key_constraints kc
JOIN sys.tables t ON kc.parent_object_id = t.object_id
JOIN sys.schemas s ON t.schema_id = t.schema_id
WHERE s.[name] = N'dbo'
AND t.[name] = N'YourTable'
AND kc.[type] = 'PK');
EXEC sys.sp_executesql #SQL;
I have several tables with a foreign key constraint that has the option ON DELETE CASCADE. Every table belongs to the same schema called datasets.
I'm able to retrieve the complete list of tables using :
SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA ='datasets'
For each table I would like to remove the ON DELETE CASCADE option on the foreign key constraint named FK_[TABLENAME]_SerieID where [TABLENAME] corresponds to the name of the table (and SerieId is the same foreign key across tables).
I am able to perform the operation for a particular table, for instance the table called Table1 using :
ALTER TABLE datasets.Table1
DROP CONSTRAINT FK_Table1_SerieID
ALTER TABLE datasets.Table1
ADD CONSTRAINT FK_Table1_SerieID
FOREIGN KEY (Serie_Id) REFERENCES[dbo].[Serie](SerieID)
ON DELETE NO ACTION
GO
I would like to perform the above operation for each table that belong to the schema datasets . I'm new to T-SQL and I don't know how to do it.
Should I use a cursor? Can you help me with this?
I'm using SQL Server 2016.
I would not reinvent the wheel. There is excellent script written by Aaron Bertrand: Drop and Re-Create All Foreign Key Constraints in SQL Server.
You could easily extend it to handle NO ACTION case and specific schema by adding simple WHERE restriction:
DECLARE #drop NVARCHAR(MAX) = N'',
#create NVARCHAR(MAX) = N'';
-- drop is easy,just build a simple concatenated list from sys.foreign_keys:
SELECT #drop += N'
ALTER TABLE ' + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name)
+ ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS ct
ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs
ON ct.[schema_id] = cs.[schema_id]
WHERE delete_referential_action_desc <> 'NO_ACTION' -- here
AND cs.name = 'datasets';
-- create is a little more complex. We need to generate the list of
-- columns on both sides of the constraint, even though in most cases
-- there is only one column.
SELECT #create += N'
ALTER TABLE '
+ QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name)
+ ' ADD CONSTRAINT ' + QUOTENAME(fk.name)
+ ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
-- get all the columns in the constraint table
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.parent_column_id = c.column_id
AND fkc.parent_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'),1,1,N'')
+ ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name)
+ '(' + STUFF((SELECT ',' + QUOTENAME(c.name)
-- get all the referenced columns
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.referenced_column_id = c.column_id
AND fkc.referenced_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'),1,1,N'') + ');'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS rt -- referenced table
ON fk.referenced_object_id = rt.[object_id]
INNER JOIN sys.schemas AS rs
ON rt.[schema_id] = rs.[schema_id]
INNER JOIN sys.tables AS ct -- constraint table
ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs
ON ct.[schema_id] = cs.[schema_id]
WHERE rt.is_ms_shipped = 0 AND ct.is_ms_shipped = 0
AND delete_referential_action_desc <> 'NO_ACTION' -- here
AND cs.name = 'datasets';
print(#drop);
print(#create);
-- ...
DBFiddle Demo
One warning! Please avoid adding ORDER BY.
This script uses
SELECT #drop += N'...'
<=>
SELECT #drop = #drop + N'...'
and it may start producing incorrect results. More nvarchar concatenation / index / nvarchar(max) inexplicable behavior
I am trying to drop all tables in a database without having to do it in the proper order. From what I have read running the NOCHECK command will prevent foreign keys from being checked. However, even after running that I still get an error trying to drop the first table.
Could not drop object 'dbo.TABLENAME' because it is referenced by
a FOREIGN KEY constraint
I have seen this question answered successfully before so I don't understand what is different with what I am doing. This is running on SQL Server 2008 R2.
BEGIN TRANSACTION
--get current list of tables
SELECT QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) as 'Dropped Table'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
--disable constraint checking in all tables
DECLARE #sql NVARCHAR(max)
SET #sql = ''
SELECT #sql += ' ALTER TABLE ' + QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + ' NOCHECK CONSTRAINT ALL; '
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
select #sql
Exec sp_executesql #sql
--disable all constraints (this also didn't work)
--EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
--drop all tables
SET #sql = ''
SELECT #sql += ' DROP TABLE ' + QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + '; '
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
select #sql
Exec sp_executesql #sql
--check current list, should be empty
SELECT QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) as 'Tables'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
ROLLBACK TRANSACTION
Update 1
I removed the constraint disabling code in place of constraint dropping code but it gives and error.
--drop all constraints
DECLARE #sql NVARCHAR(max)
SET #sql = ''
SELECT #sql += ' ALTER TABLE ' +QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + ' DROP CONSTRAINT ' + ctu.CONSTRAINT_NAME + ';'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
INNER JOIN EOS_DEV.INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE as ctu
ON ctu.TABLE_SCHEMA = s.name AND ctu.TABLE_NAME = t.name
WHERE t.type = 'U'
Exec sp_executesql #sql
The constraint '[CONSTRAINT_NAME]' is being referenced by table
'[TABLE_NAME]', foreign key constraint '[FK_NAME]'
How can I modify this query so I only target FK constraints?
Thanks everyone for your help. I updated my query and can now confirm that it has the ability to drop all tables indiscriminately. I also added a section to drop all stored procs for a little added flavor.
BEGIN TRANSACTION
--get current list of tables
SELECT QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) as 'Dropped Table'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
--drop all constraints
DECLARE #sql NVARCHAR(max)
SET #sql = ''
SELECT #sql += ' ALTER TABLE ' +QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + ' DROP CONSTRAINT ' + tc.CONSTRAINT_NAME + ';'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
INNER JOIN EOS_DEV.INFORMATION_SCHEMA.TABLE_CONSTRAINTS as tc
ON tc.TABLE_SCHEMA = s.name AND tc.TABLE_NAME = t.name
WHERE t.type = 'U'
AND tc.CONSTRAINT_TYPE = 'FOREIGN KEY'
Exec sp_executesql #sql
--drop all tables
SET #sql = ''
SELECT #sql += ' DROP TABLE ' + QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + '; '
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
Exec sp_executesql #sql
--drop all stored procs
SET #sql = ''
SELECT #sql += 'DROP PROCEDURE [' + SCHEMA_NAME(p.schema_id) + '].[' + p.NAME + ']'
FROM sys.procedures as p
where p.is_ms_shipped = 0
AND p.type = 'P'
Exec sp_executesql #sql
ROLLBACK TRANSACTION
Setting a FK to NOCHECK will allow you to INSERT,UPDATE, or DELETE rows that would violate the constraint. It will not allow you to DROP or TRUNCATE the target table.
EG:
use tempdb
create table a(id int primary key)
create table b(id int primary key, aid int references a)
alter table b nocheck constraint all
insert into b(id,aid) values (1,1) --succeeds because of nocheck
drop table a --fails
--Msg 3726, Level 16, State 1, Line 11
--Could not drop object 'a' because it is referenced by a FOREIGN KEY constraint.
Do you have to make this so difficult? Why not just restore an empty database (or a database that contains just your schema and whatever "default" rows are needed)?
I have the following:
DROP TABLE [dbo].[ExtraUserInformation];
DROP TABLE [dbo].[UserProfile];
DROP TABLE [dbo].[webpages_Membership];
DROP TABLE [dbo].[webpages_OAuthMembership];
DROP TABLE [dbo].[webpages_Roles];
DROP TABLE [dbo].[webpages_UsersInRoles];
CREATE TABLE [dbo].[ExtraUserInformation] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[UserId] INT NOT NULL,
[FullName] NVARCHAR (MAX) NULL,
[Link] NVARCHAR (MAX) NULL,
[Verified] BIT NULL,
CONSTRAINT [PK_dbo.ExtraUserInformation] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[webpages_UsersInRoles] (
[UserId] INT NOT NULL,
[RoleId] INT NOT NULL,
PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC),
CONSTRAINT [fk_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[UserProfile] ([UserId]),
CONSTRAINT [fk_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[webpages_Roles] ([RoleId])
);
However this is failing with a message saying:
Msg 3726, Level 16, State 1, Line 6
Could not drop object 'dbo.UserProfile' because it is referenced by a FOREIGN KEY constraint.
Msg 3726, Level 16, State 1, Line 9
Could not drop object 'dbo.webpages_Roles' because it is referenced by a FOREIGN KEY constraint.
Msg 2714, Level 16, State 6, Line 27
There is already an object named 'UserProfile' in the database.
Checking identity information: current identity value 'NULL', current column value 'NULL'.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
How can I drop a table in these circumstances?
You must drop the constraint before you can drop the table. Otherwise its rule violation that could break the databases Referential Integrity.
How to get foreign key relationships see this old question.
SQL DROP TABLE foreign key constraint
1-firstly, drop the foreign key constraint after that drop the tables.
2-you can drop all foreign key via executing the following query:
DECLARE #SQL varchar(4000)=''
SELECT #SQL =
#SQL + 'ALTER TABLE ' + s.name+'.'+t.name + ' DROP CONSTRAINT [' + RTRIM(f.name) +'];' + CHAR(13)
FROM sys.Tables t
INNER JOIN sys.foreign_keys f ON f.parent_object_id = t.object_id
INNER JOIN sys.schemas s ON s.schema_id = f.schema_id
--EXEC (#SQL)
PRINT #SQL
if you execute the printed results #SQL, the foreign keys will be dropped.
The Best Answer to dropping the table containing foreign constraints is :
Step 1 : Drop the Primary key of the table.
Step 2 : Now it will prompt whether to delete all the foreign references or not.
Step 3 : Delete the table.
To drop a table if there is a foreign key constraint in MySQL Server?
Run the sql query:
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE table_name
Hope it helps!
--Find and drop the constraints
DECLARE #dynamicSQL VARCHAR(MAX)
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT dynamicSQL = 'ALTER TABLE [' + OBJECT_SCHEMA_NAME(parent_object_id) + '].[' + OBJECT_NAME(parent_object_id) + '] DROP CONSTRAINT [' + name + ']'
FROM sys.foreign_keys
WHERE object_name(referenced_object_id) in ('table1', 'table2', 'table3')
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO #dynamicSQL
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #dynamicSQL
EXEC (#dynamicSQL)
FETCH NEXT FROM MY_CURSOR INTO #dynamicSQL
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
-- Drop tables
DROP 'table1'
DROP 'table2'
DROP 'table3'
You have to drop the constraint before drop your table.
You can use those queries to find all FKs in your table and find the FKs in the tables in which your table is used.
Declare #SchemaName VarChar(200) = 'Your Schema name'
Declare #TableName VarChar(200) = 'Your Table Name'
-- Find FK in This table.
SELECT
' IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id =
OBJECT_ID(N''' +
'[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' + FK.name + ']'
+ ''') AND parent_object_id = OBJECT_ID(N''' +
'[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' +
OBJECT_NAME(FK.parent_object_id) + ']' + ''')) ' +
'ALTER TABLE ' + OBJECT_SCHEMA_NAME(FK.parent_object_id) +
'.[' + OBJECT_NAME(FK.parent_object_id) +
'] DROP CONSTRAINT ' + FK.name
, S.name , O.name, OBJECT_NAME(FK.parent_object_id)
FROM sys.foreign_keys AS FK
INNER JOIN Sys.objects As O
ON (O.object_id = FK.parent_object_id )
INNER JOIN SYS.schemas AS S
ON (O.schema_id = S.schema_id)
WHERE
O.name = #TableName
And S.name = #SchemaName
-- Find the FKs in the tables in which this table is used
SELECT
' IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id =
OBJECT_ID(N''' +
'[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' + FK.name + ']'
+ ''') AND parent_object_id = OBJECT_ID(N''' +
'[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' +
OBJECT_NAME(FK.parent_object_id) + ']' + ''')) ' +
' ALTER TABLE ' + OBJECT_SCHEMA_NAME(FK.parent_object_id) +
'.[' + OBJECT_NAME(FK.parent_object_id) +
'] DROP CONSTRAINT ' + FK.name
, S.name , O.name, OBJECT_NAME(FK.parent_object_id)
FROM sys.foreign_keys AS FK
INNER JOIN Sys.objects As O
ON (O.object_id = FK.referenced_object_id )
INNER JOIN SYS.schemas AS S
ON (O.schema_id = S.schema_id)
WHERE
O.name = #TableName
And S.name = #SchemaName
BhupeshC and murat , this is what I was looking for. However #SQL varchar(4000) wasn't big enough. So, small change
DECLARE #cmd varchar(4000)
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
select 'ALTER TABLE ['+s.name+'].['+t.name+'] DROP CONSTRAINT [' + RTRIM(f.name) +'];' FROM sys.Tables t INNER JOIN sys.foreign_keys f ON f.parent_object_id = t.object_id INNER JOIN sys.schemas s ON s.schema_id = f.schema_id
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO #cmd
WHILE ##FETCH_STATUS = 0
BEGIN
-- EXEC (#cmd)
PRINT #cmd
FETCH NEXT FROM MY_CURSOR INTO #cmd
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
GO
Re removing constraints and dropping the tables, this script can get all constraints for a selected list of tables and then drop the constraints and then delete the tables.
DECLARE #id INT
DECLARE #strSQL NVARCHAR(max)
DECLARE #deleteCurser CURSOR
DECLARE #deleteTableCurser CURSOR
declare #SelectedTables table ([name] sysname, [object_id] int)
Insert into #SelectedTables ([name], [object_id])
SELECT t.name, t.object_id
FROM sys.Tables t
where t.name in
-- Change Name of tables here
('table1','table2','table100')
SET #deleteTableCurser = CURSOR FOR
SELECT strSQL =
'ALTER TABLE ' + s.name+'.'+t.name + ' DROP CONSTRAINT [' + RTRIM(f.name) +'];'
FROM #SelectedTables t
INNER JOIN sys.foreign_keys f ON f.parent_object_id = t.object_id
INNER JOIN sys.schemas s ON s.schema_id = f.schema_id
OPEN #deleteTableCurser
FETCH Next
FROM #deleteTableCurser INTO #strSQL
WHILE ##FETCH_STATUS = 0
BEGIN
print(#strSQL)
EXEC (#strSQL)
FETCH NEXT
FROM #deleteTableCurser INTO #strSQL
END
CLOSE #deleteTableCurser
DEALLOCATE #deleteTableCurser
SET #deleteCurser = CURSOR FOR
SELECT strSQL = 'DROP TABLE ['+ t.name+ '];'
FROM #SelectedTables t
OPEN #deleteCurser
FETCH Next
FROM #deleteCurser INTO #strSQL
WHILE ##FETCH_STATUS = 0
BEGIN
print(#strSQL)
EXEC (#strSQL)
FETCH NEXT
FROM #deleteCurser INTO #strSQL
END
CLOSE #deleteCurser
DEALLOCATE #deleteCurser
Type this .... SET foreign_key_checks = 0;
delete your table then type SET foreign_key_checks = 1;
MySQL – Temporarily disable Foreign Key Checks or Constraints
How to drop a column which is having Default constraint in SQL Server 2008?
My query is
alter table tbloffers
drop column checkin
I am getting below error
ALTER TABLE DROP COLUMN checkin failed because one or more objects access this column.
Can anyone correct my query to drop a column with constraint?
First you should drop the problematic DEFAULT constraint, after that you can drop the column
alter table tbloffers drop constraint [ConstraintName]
go
alter table tbloffers drop column checkin
But the error may appear from other reasons - for example the user defined function or view with SCHEMABINDING option set for them.
UPD:
Completely automated dropping of constraints script:
DECLARE #sql NVARCHAR(MAX)
WHILE 1=1
BEGIN
SELECT TOP 1 #sql = N'alter table tbloffers drop constraint ['+dc.NAME+N']'
from sys.default_constraints dc
JOIN sys.columns c
ON c.default_object_id = dc.object_id
WHERE
dc.parent_object_id = OBJECT_ID('tbloffers')
AND c.name = N'checkin'
IF ##ROWCOUNT = 0 BREAK
EXEC (#sql)
END
Here's another way to drop a default constraint with an unknown name without having to first run a separate query to get the constraint name:
DECLARE #ConstraintName nvarchar(200)
SELECT #ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS
WHERE PARENT_OBJECT_ID = OBJECT_ID('__TableName__')
AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns
WHERE NAME = N'__ColumnName__'
AND object_id = OBJECT_ID(N'__TableName__'))
IF #ConstraintName IS NOT NULL
EXEC('ALTER TABLE __TableName__ DROP CONSTRAINT ' + #ConstraintName)
You can also drop the column and its constraint(s) in a single statement rather than individually.
CREATE TABLE #T
(
Col1 INT CONSTRAINT UQ UNIQUE CONSTRAINT CK CHECK (Col1 > 5),
Col2 INT
)
ALTER TABLE #T DROP CONSTRAINT UQ ,
CONSTRAINT CK,
COLUMN Col1
DROP TABLE #T
Some dynamic SQL that will look up the names of dependent check constraints and default constraints and drop them along with the column is below
(but not other possible column dependencies such as foreign keys, unique and primary key constraints, computed columns, indexes)
CREATE TABLE [dbo].[TestTable]
(
A INT DEFAULT '1' CHECK (A=1),
B INT,
CHECK (A > B)
)
GO
DECLARE #TwoPartTableNameQuoted nvarchar(500) = '[dbo].[TestTable]',
#ColumnNameUnQuoted sysname = 'A',
#DynSQL NVARCHAR(MAX);
SELECT #DynSQL =
'ALTER TABLE ' + #TwoPartTableNameQuoted + ' DROP' +
ISNULL(' CONSTRAINT ' + QUOTENAME(OBJECT_NAME(c.default_object_id)) + ',','') +
ISNULL(check_constraints,'') +
' COLUMN ' + QUOTENAME(#ColumnNameUnQuoted)
FROM sys.columns c
CROSS APPLY (SELECT ' CONSTRAINT ' + QUOTENAME(OBJECT_NAME(referencing_id)) + ','
FROM sys.sql_expression_dependencies
WHERE referenced_id = c.object_id
AND referenced_minor_id = c.column_id
AND OBJECTPROPERTYEX(referencing_id, 'BaseType') = 'C'
FOR XML PATH('')) ck(check_constraints)
WHERE c.object_id = object_id(#TwoPartTableNameQuoted)
AND c.name = #ColumnNameUnQuoted;
PRINT #DynSQL;
EXEC (#DynSQL);
Find the default constraint with this query here:
SELECT
df.name 'Constraint Name' ,
t.name 'Table Name',
c.NAME 'Column Name'
FROM sys.default_constraints df
INNER JOIN sys.tables t ON df.parent_object_id = t.object_id
INNER JOIN sys.columns c ON df.parent_object_id = c.object_id AND df.parent_column_id = c.column_id
This gives you the name of the default constraint, as well as the table and column name.
When you have that information you need to first drop the default constraint:
ALTER TABLE dbo.YourTable
DROP CONSTRAINT name-of-the-default-constraint-here
and then you can drop the column
ALTER TABLE dbo.YourTable DROP COLUMN YourColumn
The following worked for me against a SQL Azure backend (using SQL Server Management Studio), so YMMV, but, if it works for you, it's waaaaay simpler than the other solutions.
ALTER TABLE MyTable
DROP CONSTRAINT FK_MyColumn
CONSTRAINT DK_MyColumn
-- etc...
COLUMN MyColumn
GO
Based on the previous answers, I have added it as a stored procedure to simplify the deletion of a column when it has attached constraints
CREATE OR ALTER PROC DROP_COLUMN(#TableName nvarchar(200), #ColumnName nvarchar(200))
AS
BEGIN
DECLARE #ConstraintName nvarchar(200)
SELECT #ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS
WHERE PARENT_OBJECT_ID = OBJECT_ID(#TableName)
AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns
WHERE NAME = #ColumnName
AND object_id = OBJECT_ID(#TableName))
IF #ConstraintName IS NOT NULL
EXEC('ALTER TABLE '+#TableName+' DROP CONSTRAINT ' + #ConstraintName)
EXEC('ALTER TABLE '+#TableName+' DROP COLUMN IF EXISTS ' + #ColumnName)
END
GO
--example:
EXEC DROP_COLUMN N'VEHICLES', N'SCMT'
EXEC DROP_COLUMN N'VEHICLES', N'SSC'
EXEC DROP_COLUMN N'VEHICLES', N'RS'
EXEC DROP_COLUMN N'VEHICLES', N'RCEC'
DROP PROCEDURE IF EXISTS DROP_COLUMN
I got the same:
ALTER TABLE DROP COLUMN failed because one or more objects access this column message.
My column had an index which needed to be deleted first. Using sys.indexes did the trick:
DECLARE #sql VARCHAR(max)
SELECT #sql = 'DROP INDEX ' + idx.NAME + ' ON tblName'
FROM sys.indexes idx
INNER JOIN sys.tables tbl ON idx.object_id = tbl.object_id
INNER JOIN sys.index_columns idxCol ON idx.index_id = idxCol.index_id
INNER JOIN sys.columns col ON idxCol.column_id = col.column_id
WHERE idx.type <> 0
AND tbl.NAME = 'tblName'
AND col.NAME = 'colName'
EXEC sp_executeSql #sql
GO
ALTER TABLE tblName
DROP COLUMN colName
I have updated script a little bit to my SQL server version
DECLARE #sql nvarchar(max)
SELECT #sql = 'ALTER TABLE `table_name` DROP CONSTRAINT ' + df.NAME
FROM sys.default_constraints df
INNER JOIN sys.tables t ON df.parent_object_id = t.object_id
INNER JOIN sys.columns c ON df.parent_object_id = c.object_id AND df.parent_column_id = c.column_id
where t.name = 'table_name' and c.name = 'column_name'
EXEC sp_executeSql #sql
GO
ALTER TABLE table_name
DROP COLUMN column_name;
It's not always just a default constraint that prevents from droping a column and sometimes indexes can also block you from droping the constraint.
So I wrote a procedure that drops any index or constraint on a column and the column it self at the end.
IF OBJECT_ID ('ADM_delete_column', 'P') IS NOT NULL
DROP procedure ADM_delete_column;
GO
CREATE procedure ADM_delete_column
#table_name_in nvarchar(300)
, #column_name_in nvarchar(300)
AS
BEGIN
/* Author: Matthis (matthis#online.ms at 2019.07.20)
License CC BY (creativecommons.org)
Desc: Administrative procedure that drops columns at MS SQL Server
- if there is an index or constraint on the column
that will be dropped in advice
=> input parameters are TABLE NAME and COLUMN NAME as STRING
*/
SET NOCOUNT ON
--drop index if exist (search first if there is a index on the column)
declare #idx_name VARCHAR(100)
SELECT top 1 #idx_name = i.name
from sys.tables t
join sys.columns c
on t.object_id = c.object_id
join sys.index_columns ic
on c.object_id = ic.object_id
and c.column_id = ic.column_id
join sys.indexes i
on i.object_id = ic.object_id
and i.index_id = ic.index_id
where t.name like #table_name_in
and c.name like #column_name_in
if #idx_name is not null
begin
print concat('DROP INDEX ', #idx_name, ' ON ', #table_name_in)
exec ('DROP INDEX ' + #idx_name + ' ON ' + #table_name_in)
end
--drop fk constraint if exist (search first if there is a constraint on the column)
declare #fk_name VARCHAR(100)
SELECT top 1 #fk_name = CONSTRAINT_NAME
from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
where TABLE_NAME like #table_name_in
and COLUMN_NAME like #column_name_in
if #fk_name is not null
begin
print concat('ALTER TABLE ', #table_name_in, ' DROP CONSTRAINT ', #fk_name)
exec ('ALTER TABLE ' + #table_name_in + ' DROP CONSTRAINT ' + #fk_name)
end
--drop column if exist
declare #column_name VARCHAR(100)
SELECT top 1 #column_name = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME like concat('%',#column_name_in,'%')
if #column_name is not null
begin
print concat('ALTER TABLE ', #table_name_in, ' DROP COLUMN ', #column_name)
exec ('ALTER TABLE ' + #table_name_in + ' DROP COLUMN ' + #column_name)
end
end;
GO
--to run the procedure use this execute and fill the parameters
execute ADM_delete_column
#table_name_in = ''
, #column_name_in = ''
;