如何删除约束列?


138

如何在SQL Server 2008中删除具有默认约束的列?

我的查询是

alter table tbloffers
drop column checkin

我低于错误

ALTER TABLE DROP COLUMN签入失败,因为一个或多个对象访问此列。

谁能纠正我的查询以删除具有约束的列?


可能是其他表对此表的某些引用导致此错误。
Pankaj Upadhyay

如果您是新手,请在下面查看我的答案,如果它对您有用,那么它比其他一些解决方案要简单得多。
BrainSlugs83

Answers:


233

首先,您应该删除有问题的对象DEFAULT constraint,之后可以删除该列

alter table tbloffers drop constraint [ConstraintName]
go

alter table tbloffers drop column checkin

但是错误可能是由其他原因引起的-例如,用户定义的功能或SCHEMABINDING为其设置选项的视图。

UPD: 完全自动删除约束脚本:

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

1
感谢您的自动化脚本。奇迹般有效!
kanadianDri3 '16

非常感谢您-您节省了我很多时间。我已将我提出的问题链接到这里了
Akash Yellappa

130

这是删除具有未知名称的默认约束的另一种方法,而不必首先运行单独的查询来获取约束名称:

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)

很棒的答案,谢谢。不过,我确实赞成上面的答案,只是出于那种在选择删除之前先选择和检查的fl弱习惯。
noogrub 2014年

7
确实是个好答案。为了方便/将来使用,我从中
Digs

当一个列有多个约束时,答案很好,但仍然缺少方法。一些类似于@Digs的带有循环的已存储过程,可能包括5星的答案
YeinCM-Qva

27

您还可以将列及其约束放到一个语句中,而不要单独放。

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 

一些动态SQL将查找相关检查约束和默认约束的名称,并将其与下面的列一起删除

(但不是其他可能的列依赖性,例如外键,唯一键和主键约束,计算列,索引)

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

但是,这需要您知道约束的名称。如果在创建表期间未对它们进行命名,则会获得一个自动生成的名称。
2012年

1
@Joey-在不知道名称的情况下没有语法可以删除约束。这是DROP CONSTRAINT 查看语法的必需参数。如果未明确命名约束,则必须查找为其生成的SQL Server名称,例如,根据marc的答案。但是发现了这些之后,您仍然可以同时删除约束和列。
马丁·史密斯

好的代码,我需要立即删除多个约束,但不要删除该列。您的变更成功了。谢谢!!
htm11h 2013年

26

在此查询中找到默认约束:

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

这为您提供了默认约束的名称,以及表和列的名称。

掌握了这些信息后,您需要首先删除默认约束:

ALTER TABLE dbo.YourTable
DROP CONSTRAINT name-of-the-default-constraint-here

然后您可以删除该列

ALTER TABLE dbo.YourTable DROP COLUMN YourColumn

2
不必按顺序进行。您可以同时执行它们。
马丁·史密斯

1
@MartinSmith:好的,很好-感谢分享!我没有意识到这种可能性-您每天都会学到新东西!:-)
marc_s

有人可以提供一个示例,说明如何组合这两个语句。我需要一些ALTER TABLE table DROP CONSTRAINT DF_XY DROP COLUMN XY思考:不幸的是,该语句的语法不正确
My-Name-Is

1
@ My-Name-Is:如果您查看Martin的答案,则需要在两个命令之间加上逗号DROP以使其起作用
marc_s

3

以下内容对我来说适用于SQL Azure后端(使用SQL Server Management Studio),因此YMMV,但是,如果它对您有用,则比其他解决方案更简单。

ALTER TABLE MyTable
    DROP CONSTRAINT FK_MyColumn
    CONSTRAINT DK_MyColumn
    -- etc...
    COLUMN MyColumn
GO

1

我也一样:

ALTER TABLE DROP COLUMN失败,因为一个或多个对象访问此列消息。

我的专栏有一个索引,需要首先删除。使用sys.indexes可以达到目的:

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

0

我已将脚本更新到我的SQL Server版本

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;

0

并非总是默认约束会阻止删除列,有时索引也会阻止您删除约束。因此,我编写了一个过程,该过程将任何索引或约束放在一列上,并将其自身列在末尾。

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 = ''
    ;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.