194

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?

4
  • there might be some references to this table from other tables which is causing this error. Commented Dec 27, 2011 at 6:59
  • For new comers stumbling on to this, check out my answer below, if it works for you, it's way simpler than some of the other solutions. Commented Oct 4, 2017 at 20:21
  • I've listed my question and answer here Commented Jun 20, 2019 at 17:49
  • For Oracle - if you just drop the column, it will also drop the constraint for you. Commented Aug 31, 2023 at 13:26

12 Answers 12

301

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
Sign up to request clarification or add additional context in comments.

Comments

189

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)

5 Comments

A superb answer, thank you. I did upvote the above answer also, though, just out of that flinchy old habit of SELECTing and inspecting first before deciding to drop.
Great answer indeed. I made a stored procedure out of it for convenience / future use: pastebin.com/2CeXZDh2
Excellent answer but still missing approach when there are more than one constraint tied to a column. Some stored proc similar to @Digs ' post with loop included could be 5 stars answer
This method is very simple yet effective.
great answer indeed, but does not work in 2024. Please check my answer below for the updated version of the same. stackoverflow.com/a/78137938/1880899
31

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); 

3 Comments

This requires you to know the name of the constraint, though. If they ahven't been named during table creation they get an automatically-generated name.
@Joey - There is no syntax to drop constraints without knowing the name. It is a required argument to DROP CONSTRAINT see grammar If you don't name the constraints explicitly then you'll have to look up the name SQL Server generated for it e.g. as per marc's answer. But having found that out you can still drop the constraint and column at the same time.
Nice code, I needed to drop mulitple constraints at once, but not the column. Your alter did the trick. Thanks!!
30

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

4 Comments

It doesn't have to be done sequentially. You can do them both at the same time.
@MartinSmith: OK, great - thanks for sharing! I wasn't aware of this possibility - you learn something new every day! :-)
Can someone please provide an example for how to combine these two statements. I need somethink like: ALTER TABLE table DROP CONSTRAINT DF_XY DROP COLUMN XY Unfortunately the syntax of this statement isn't correct
@My-Name-Is: if you check out Martin's answer, you need to put a comma between the two DROP commands to make this work
5

a bit simpler drop constraint by table name and column name:

DECLARE @ConstraintName NVARCHAR(100)
SELECT @ConstraintName = OBJECT_NAME([default_object_id])
FROM SYS.COLUMNS
WHERE [object_id] = OBJECT_ID('[my_table_name]') AND [name] = 'my_column_name';
EXEC('ALTER TABLE [my_table_name] DROP CONSTRAINT ' + @ConstraintName)

Comments

3

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

Comments

3

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;

Comments

3

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 

Comments

2

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 ([email protected] 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 = ''
    ;

2 Comments

I like this script, thanks! Please update it to include the table name in where clause of "drop column if exist" part to prevent crashes. WHERE COLUMN_NAME like concat('%',@column_name_in,'%') AND TABLE_NAME like concat('%',@table_name_in,'%')
I think your answer is the most comprehensive. But you have to consider that a column can have more than a single constraint (a default, one or more foreign keys, one or more checks) and more than a single index (some indexes can include more than a signle column and a single column can be used in more multicolumn indexes). You should use cursors to drop all indexes and constraints! You should to consider to include the schema name over than the table name (and if it is null, use the default current user schema). In this way your routine is comprehensive and complete.
1

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

Comments

1

@chris-halcrow's answer was great indeed but it does not work in 2024 anymore. here is the updated version of the same.

UPDATE 2024 Sql Server V2019

DECLARE @ConstraintName NVARCHAR(200)
SELECT @ConstraintName = name FROM SYS.default_constraints WHERE object_id = (
    SELECT default_object_id FROM sys.columns WHERE name = '<ColumnName>'
)
IF @ConstraintName IS NOT NULL
    EXEC('ALTER TABLE <TableName> DROP CONSTRAINT ' + @ConstraintName)

Comments

0

Using Design Tool in SQL-Server:

There are some built in tools availabe in the SQL Server that can make life easy for developers.

Replicating the Problem

CREATE TABLE demo..Person (
    PersonID int default 0,
    LastName varchar(255),
)

-- Dropping the Column

alter table demo..Person drop column PersonID

Error

The object 'DF__Person__PersonID__0DE74436' is dependent on column 'PersonID'.
Msg 4922, Level 16, State 9, Line 8
ALTER TABLE DROP COLUMN PersonID failed because one or more objects access this column.

Solution:

Solution using the design tool of SQL Server 2019.

Solution

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.