我有一个带有"DEFAULT"约束的列.我想创建一个删除该列的脚本.
问题是它返回此错误:
Msg 5074, Level 16, State 1, Line 1 The object 'DF__PeriodSce__IsClo__4BCC3ABA' is dependent on column 'IsClosed'. Msg 4922, Level 16, State 9, Line 1 ALTER TABLE DROP COLUMN IsClosed failed because one or more objects access this column.
我找不到一种简单的方法来删除一个列及其所有相关的约束(只发现了查看系统表的大脚本......必须(!!)这是一个"好"的方法.)
由于DEFAULT约束的名称是随机生成的,我不能按名称删除它.
更新:
约束类型为"DEFAULT".
我看到了你们提出的解决方案,但我发现它们都非常"脏"......你不觉得吗?我不知道它是用于Oracle还是MySQL,但它可以做类似的事情:
DROP COLUMN xxx CASCADE CONSTRAINTS
它会丢弃所有相关的约束......或者至少它会自动删除映射到该列的约束(至少CHECK约束!)
在MSSQL中没有类似的东西吗?
这是一个脚本,它将删除列及其默认约束.替换MYTABLENAME
并MYCOLUMNNAME
适当.
declare @constraint_name sysname, @sql nvarchar(max) select @constraint_name = name from sys.default_constraints where parent_object_id = object_id('MYTABLENAME') AND type = 'D' AND parent_column_id = ( select column_id from sys.columns where object_id = object_id('MYTABLENAME') and name = 'MYCOLUMNNAME' ) set @sql = N'alter table MYTABLENAME drop constraint ' + @constraint_name exec sp_executesql @sql alter table MYTABLENAME drop column MYCOLUMNNAME go
此查询查找给定表的默认约束.它不是很好,我同意:
select col.name, col.column_id, col.default_object_id, OBJECTPROPERTY(col.default_object_id, N'IsDefaultCnst') as is_defcnst, dobj.name as def_name from sys.columns col left outer join sys.objects dobj on dobj.object_id = col.default_object_id and dobj.type = 'D' where col.object_id = object_id(N'dbo.test') and dobj.name is not null
[编辑]根据Julien N的评论更新
也许它可以帮助更多:
declare @tablename nvarchar(200) declare @colname nvarchar(200) declare @default sysname, @sql nvarchar(max) set @tablename = 'your table' set @colname = 'column to drop' select @default = name from sys.default_constraints where parent_object_id = object_id(@tablename) AND type = 'D' AND parent_column_id = ( select column_id from sys.columns where object_id = object_id(@tablename) and name = @colname ) set @sql = N'alter table ' + @tablename + ' drop constraint ' + @default exec sp_executesql @sql set @sql = N'alter table ' + @tablename + ' drop column ' + @colname exec sp_executesql @sql
只需要设置@tablename和@colname变量来删除列.
> select CONSTRAINT_NAME from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE > WHERE TABLE_NAME = '' AND COLUMN_NAME = 'IsClosed'
这不是正确的解决方案,因为它在这里解释:http://msdn.microsoft.com/en-us/library/aa175912.aspx:
遗憾的是,列默认约束的名称未保留在ANSI COLUMNS视图中,因此您必须返回系统表才能找到名称
我发现获取DEFAULT约束名称的唯一方法是此请求:
select t_obj.name as TABLE_NAME ,c_obj.name as CONSTRAINT_NAME ,col.name as COLUMN_NAME from sysobjects c_obj join sysobjects t_obj on c_obj.parent_obj = t_obj.id join sysconstraints con on c_obj.id = con.constid join syscolumns col on t_obj.id = col.id and con.colid = col.colid where c_obj.xtype = 'D'
我是唯一一个发现它的疯狂是不能轻易删除的约束,只有涉及我试图删除列?
我需要执行一个带有3个连接的请求才能获得名称...
我也认为在SQL服务器中没有可用的级联丢包是一个缺点.我通过查询系统表来解决这个问题,方法与此处描述的其他人一样:
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE仅列出外键,主键和唯一约束.
查找默认约束的唯一方法是在sys.default_constraints中查找它们.
这里还没有提到的是,索引也会导致删除列失败,因此您还需要删除使用列的所有索引,然后才能继续删除列.
生成的脚本不漂亮,但我将它放在存储过程中以便能够重用它:
CREATE PROCEDURE DropColumnCascading @tablename nvarchar(500), @columnname nvarchar(500) AS SELECT CONSTRAINT_NAME, 'C' AS type INTO #dependencies FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_NAME = @tablename AND COLUMN_NAME = @columnname INSERT INTO #dependencies select d.name, 'C' from sys.default_constraints d join sys.columns c ON c.column_id = d.parent_column_id AND c.object_id = d.parent_object_id join sys.objects o ON o.object_id = d.parent_object_id WHERE o.name = @tablename AND c.name = @columnname INSERT INTO #dependencies SELECT i.name, 'I' FROM sys.indexes i JOIN sys.index_columns ic ON ic.index_id = i.index_id and ic.object_id=i.object_id JOIN sys.columns c ON c.column_id = ic.column_id and c.object_id=i.object_id JOIN sys.objects o ON o.object_id = i.object_id where o.name = @tableName AND i.type=2 AND c.name = @columnname AND is_unique_constraint = 0 DECLARE @dep_name nvarchar(500) DECLARE @type nchar(1) DECLARE dep_cursor CURSOR FOR SELECT * FROM #dependencies OPEN dep_cursor FETCH NEXT FROM dep_cursor INTO @dep_name, @type; DECLARE @sql nvarchar(max) WHILE @@FETCH_STATUS = 0 BEGIN SET @sql = CASE @type WHEN 'C' THEN 'ALTER TABLE [' + @tablename + '] DROP CONSTRAINT [' + @dep_name + ']' WHEN 'I' THEN 'DROP INDEX [' + @dep_name + '] ON dbo.[' + @tablename + ']' END print @sql EXEC sp_executesql @sql FETCH NEXT FROM dep_cursor INTO @dep_name, @type; END DEALLOCATE dep_cursor DROP TABLE #dependencies SET @sql = 'ALTER TABLE [' + @tablename + '] DROP COLUMN [' + @columnname + ']' print @sql EXEC sp_executesql @sql