如何删除 SQL Server 2008 中具有默认约束的列?
我的查询是
alter table tbloffers
drop column checkin
我遇到以下错误
ALTER TABLE DROP COLUMN 签入失败,因为一个或多个对象访问此列。
任何人都可以更正我的查询以删除带有约束的列吗?
首先你应该删除有问题的
DEFAULT constraint
,然后你可以删除该列
alter table tbloffers drop constraint [ConstraintName]
go
alter table tbloffers drop column checkin
但是错误可能是由其他原因导致的 - 例如用户定义的函数或视图设置了
SCHEMABINDING
选项。
更新: 完全自动删除约束脚本:
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
这是删除名称未知的默认约束的另一种方法,而无需先运行单独的查询来获取约束名称:
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)
您还可以在单个语句中而不是单独删除列及其约束。
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
(但不是其他可能的列依赖项,例如外键、唯一键和主键约束、计算列、索引)
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);
在此处查找此查询的默认约束:
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
更简单一点的通过表名和列名删除约束:
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)
以下内容对我来说适用于 SQL Azure 后端(使用 SQL Server Management Studio),所以 YMMV,但是,如果它适合您,那么它比其他解决方案简单得多。
ALTER TABLE MyTable
DROP CONSTRAINT FK_MyColumn
CONSTRAINT DK_MyColumn
-- etc...
COLUMN MyColumn
GO
根据前面的答案,我将其添加为存储过程,以简化在附加约束时删除列的过程
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
我已将脚本更新为我的 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;
我也得到了同样的结果:
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
它并不总是只是阻止删除列的默认约束,有时索引也可以阻止您删除约束。 因此,我编写了一个过程,删除列上的任何索引或约束,并在最后删除该列本身。
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 = ''
;
SQL Server 中有一些内置工具可以让开发人员的生活变得轻松。
CREATE TABLE demo..Person (
PersonID int default 0,
LastName varchar(255),
)
-- Dropping the Column
alter table demo..Person drop column PersonID
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.
使用SQL Server 2019设计工具的解决方案。
@chris-halcrow 的 answer 确实很棒,但到 2024 年就不再起作用了。 这是相同版本的更新版本。
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)