如何删除有约束的列?

如何删除 SQLServer2008中具有默认约束的列?

我的疑问是

alter table tbloffers
drop column checkin

我的错误越来越小了

由于一个或多个对象访问此列,ALTERTABLE DROPTCOLUMN 检查失败。

是否有人能够更正删除带约束的列的查询?

302499 次浏览

首先您应该删除有问题的 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

在这里查找默认约束:

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

还可以在单个语句中删除列及其约束,而不是单独删除。

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

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

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)

我也是:

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

我的专栏有一个需要首先删除的索引,使用 Sys.indexs就可以做到这一点:

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

下面的方法适用于 SQL Azure 后端(使用 SQL Server Management Studio) ,也就是 YMMV,但是,如果它适用于您,那么它比其他解决方案要简单得多。

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

我已经更新了一点我的 SQL 服务器版本的脚本

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;


它并不总是阻止删除列的默认约束,有时索引也会阻止删除约束。 因此,我编写了一个过程,该过程删除一个列上的任何索引或约束,并在最后删除该列本身。

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 = ''
;

基于前面的答案,我将其添加为存储过程,以简化在附加约束时删除列的操作

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