我有一个带有“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中没有这样的东西吗?
答案 0 :(得分:64)
这是一个将删除列及其默认约束的脚本。适当地替换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
答案 1 :(得分:21)
此查询查找给定表的默认约束。它不是很好,我同意:
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的评论更新
答案 2 :(得分:16)
答案 3 :(得分:6)
> select CONSTRAINT_NAME from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
> WHERE TABLE_NAME = '<tablename>' 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个连接的请求才能获得名称...
答案 4 :(得分:6)
我还认为在SQL服务器中没有可用的级联删除是一个缺点。我通过查询系统表来解决问题,方法与此处描述的其他人一样:
生成的脚本不漂亮,但我将它放在存储过程中以便能够重用它:
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
答案 5 :(得分:4)
您可以通过查询information_schema系统视图来获取约束名称。
select CONSTRAINT_NAME from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_NAME = '<tablename>' AND COLUMN_NAME = 'IsClosed'
答案 6 :(得分:4)
pvolders的回答正是我所需要的,但它错过了导致错误的统计数据。这是相同的代码,减去创建存储过程,加上枚举统计信息并删除它们。这是我能想到的最好的,所以如果有更好的方法来确定需要删除哪些统计数据,请添加。
DECLARE @tablename nvarchar(500),
@columnname nvarchar(500)
SELECT @tablename = 'tblProject',
@columnname = 'CountyKey'
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
INSERT INTO #dependencies
SELECT s.NAME, 'S'
FROM sys.stats AS s
INNER JOIN sys.stats_columns AS sc
ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id
INNER JOIN sys.columns AS c
ON sc.object_id = c.object_id AND c.column_id = sc.column_id
WHERE s.object_id = OBJECT_ID(@tableName)
AND c.NAME = @columnname
AND s.NAME LIKE '_dta_stat%'
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 + ']'
WHEN 'S' THEN 'DROP STATISTICS [' + @tablename + '].[' + @dep_name + ']'
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
答案 7 :(得分:4)
为了建立Jeremy Stein的答案,我为此创建了一个存储过程,并将其设置为可以用来删除具有或没有默认约束的列。它不是真正有效的,因为它两次查询sys.columns,但它有效。
CREATE PROCEDURE [dbo].[RemoveColumnWithDefaultConstraints]
-- Add the parameters for the stored procedure here
@tableName nvarchar(max),
@columnName nvarchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
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)
IF EXISTS(SELECT * FROM sys.columns WHERE Name = @columnName
AND Object_ID = Object_ID(@tableName))
EXEC('ALTER TABLE ' + @tableName + ' DROP COLUMN ' + @columnName)
END
GO
答案 8 :(得分:2)
查找约束的名称或使用MSSQL设计视图并不总是一种选择。我目前想制作一个脚本来删除带有约束的列。使用该名称不是一个选项,因为生成了名称,我想在不同的环境Dev / Sys / Prod / etc中使用该脚本。因此,不能使用该名称,因为每个环境的约束名称会有所不同。我可能需要查看系统表格,但我同意应该有一个更简单的选项。
答案 9 :(得分:1)
我相信在删除列之前明确地删除约束是一种“更清洁”的解决方案。这样,您就不会删除您可能不知道的约束。如果丢弃仍然失败,您知道还有其他限制。我喜欢控制我的数据库到底发生了什么。
另外,对drop进行脚本化显式保证了脚本,并希望结果可以完全按照你想要的方式重复。
答案 10 :(得分:0)
你是什么意思随机生成的?您可以在management studio中或通过sys.tables视图查找特定列的约束,并查找名称。
然后,您可以在删除列之前更改脚本以删除约束。这是什么类型的约束?如果它是外键约束,请确保这样做不会损害数据库中的数据完整性。
答案 11 :(得分:0)
我刚碰到这个。您可以使用MSSQL设计视图删除具有约束的列。右键单击要删除的列(有或没有约束),您可以毫无问题地删除它。哈......我看起来已经很蠢了。
答案 12 :(得分:-1)
只为表格生成脚本。在那里你可以找到所有约束的名称。