183

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?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Robin Michael Poothurai
  • 5,444
  • 7
  • 23
  • 36

10 Answers10

291

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
Dzianis Yafimau
  • 2,034
  • 1
  • 27
  • 38
Oleg Dok
  • 21,109
  • 4
  • 45
  • 54
177

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)
Chris Halcrow
  • 28,994
  • 18
  • 176
  • 206
  • 1
    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. – noogrub Jan 13 '14 at 16:46
  • 8
    Great answer indeed. I made a stored procedure out of it for convenience / future use: http://pastebin.com/2CeXZDh2 – Digs Apr 20 '15 at 09:27
  • 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 – YeinCM-Qva Aug 02 '17 at 15:02
  • This method is very simple yet effective. – Jagath Jul 20 '23 at 10:10
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); 
Martin Smith
  • 438,706
  • 87
  • 741
  • 845
  • 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 Oct 02 '12 at 10:08
  • 1
    @Joey - There is no syntax to drop constraints without knowing the name. It is a required argument to `DROP CONSTRAINT` [see grammar](http://msdn.microsoft.com/en-us/library/ms190273.aspx) 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. – Martin Smith Oct 02 '12 at 10:17
  • Nice code, I needed to drop mulitple constraints at once, but not the column. Your alter did the trick. Thanks!! – htm11h Jul 12 '13 at 16:14
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
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 2
    It doesn't have to be done sequentially. You can do them both at the same time. – Martin Smith Dec 27 '11 at 22:16
  • 1
    @MartinSmith: OK, great - thanks for sharing! I wasn't aware of this possibility - you learn something new every day! :-) – marc_s Dec 28 '11 at 05:57
  • 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 Jun 03 '13 at 16:27
  • 1
    @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 – marc_s Jun 03 '13 at 16:34
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
BrainSlugs83
  • 6,214
  • 7
  • 50
  • 56
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 
DATEx2
  • 3,585
  • 1
  • 24
  • 26
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
Atomic Star
  • 5,427
  • 4
  • 39
  • 48
1

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;

1

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 = ''
    ;
  • 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,'%') – Chili Con Code Nov 30 '22 at 14:11
1

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)
Dekeli
  • 103
  • 6