Столбец SQL Server 2005 с ограничениями
У меня есть столбец с ограничением "ПО УМОЛЧАНИЮ". Я хотел бы создать script, который удаляет этот столбец.
Проблема заключается в том, что она возвращает эту ошибку:
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 было случайно сгенерировано, я не могу отказаться от него по имени.
Обновить:
Тип ограничения - "ПО УМОЛЧАНИЮ".
Я видел решения, которые вы все предлагали, но я нахожу их всех действительно "грязными"... Разве вы не думаете?
Я не знаю, с Oracle или MySQL, но можно сделать что-то вроде:
DROP COLUMN xxx CASCADE CONSTRAINTS
И он устраняет все связанные ограничения...
Или, по крайней мере, он автоматически удаляет ограничения, сопоставленные этому столбцу (по крайней мере, ограничения CHECK!)
В MSSQL ничего подобного нет?
Ответы
Ответ 1
Этот запрос находит ограничения по умолчанию для данной таблицы. Это довольно, я согласен:
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
[EDIT] Обновлено за сообщение Julien N
Ответ 2
Вот script, который удалит столбец вместе со своим значением по умолчанию. Замените 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
Ответ 3
Возможно, это может помочь немного больше:
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 для удаления столбца.
Ответ 4
> 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'
Я единственный, кто нашел его сумасшедшим, чтобы не удалять легко ограничение, которое касается только столбцов, которые я пытаюсь удалить?
Мне нужно выполнить запрос с тремя соединениями, чтобы получить имя...
Ответ 5
Я также считаю, что недостатком на SQL-сервере не является доступный каскадный доступ. Я проработал вокруг него, запросив системные таблицы так же, как и другие люди, описанные здесь:
- INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE перечисляет только внешние ключи, первичные ключи и уникальные ограничения.
- Единственный способ поиска ограничений по умолчанию - искать их в sys.default_constraints.
- то, что еще не упоминалось здесь, заключается в том, что индексы также вызывают отказ столбца, поэтому вам также нужно отбросить все индексы, которые используют ваш столбец, прежде чем вы сможете продолжить удаление столбца.
Результат script не очень хорош, но я поместил его в хранимую процедуру, чтобы иметь возможность повторно использовать его:
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
Ответ 6
Вы можете получить имена ограничений, запросив системные представления Information_schema.
select CONSTRAINT_NAME from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_NAME = '<tablename>' AND COLUMN_NAME = 'IsClosed'
Ответ 7
Ответ от 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
Ответ 8
Чтобы ответить на вопрос Джереми Штейна, я создал для этого хранимую процедуру и настроил ее так, чтобы ее можно было использовать для удаления столбца, который имеет или не имеет ограничений по умолчанию. Это не реально эффективно, так как он дважды запрашивает sys.column, но он работает.
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
Ответ 9
Я считаю, что явное сокращение ограничений до сброса столбца является "более чистым" решением. Таким образом, вы не отказываетесь от ограничений, о которых вы, возможно, не знаете. Если падение все еще не удается, вы знаете, что есть дополнительные ограничения. Мне нравится контролировать то, что происходит с моей базой данных.
Кроме того, сценарии капель явно гарантируют script и, надеюсь, результаты будут повторяемы точно так, как вы планируете.
Ответ 10
Поиск имени contraint или использование MSSQL-дизайна не всегда является опцией. В настоящее время я хочу сделать script для удаления столбца с указанием на него. Использование имени не является параметром, поскольку имя сгенерировано, и я хочу использовать script в разных средах Dev/Sys/Prod/etc. Использование имени тогда невозможно, потому что имена ограничений будут отличаться для каждой среды. Мне, вероятно, придется заглянуть в системные таблички, но я согласен, что должен быть более простой вариант.
Ответ 11
Что значит "случайно"? Вы можете найти ограничения на конкретный столбец в студии управления или через представление sys.tables и найти имена (имена).
Затем вы можете изменить свой script, чтобы удалить ограничения перед тем, как удалить столбец. Что это за ограничение? Если это ограничение внешнего ключа, убедитесь, что это не повредит целостности данных в вашей базе данных.
Ответ 12
Я просто столкнулся с этим. Вы можете удалить столбец с ограничениями, используя представление MSSQL. Щелкните правой кнопкой мыши на столбце, который вы хотите удалить (с ограничениями или без ограничений), и вы можете удалить его без каких-либо проблем. Ха.. Я уже выглядел глупо.
Ответ 13
Просто создайте скрипты для таблицы. Там вы можете найти имя всех ограничений.